⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 lab5.c

📁 C++ Source code for writing custom characters on an LCD using ATMEGA16 microcontroler.
💻 C
字号:
// Laborator PM 5 - Accesul la o memorie seriala (externa) prin interfata TWI

#include <util/twi.h>
#include <stdio.h>
#include <string.h>

#include "uart.h"

#define PAGE_SIZE       8               // dimensiunea unei pagini de memorie
#define SLAVE_ADDRESS   0xA0            // adresa i2c a memoriei
#define MAX_ITER	    200             // cat sa astept sa termine scrierea

// Functii pentru TWI /////////////////////////////////////////////////////////
uint8_t twst;

void twi_init(void)
{
    TWSR = 0;
    TWBR = (16000000UL / 100000UL - 16) / 2;

	twst = 0;
}

// trimite un start condition
void twi_send_start(void)
{
    TWCR = _BV(TWINT) | _BV(TWSTA) | _BV(TWEN);
}

// trimite un repeated start condition
void twi_send_rep_start(void)
{
    TWCR = _BV(TWINT) | _BV(TWSTA) | _BV(TWEN);
}

// trimite un stop condition
void twi_send_stop(void)
{    
	TWCR = (1<<TWINT)|(1<<TWEN)| (1<<TWSTO);
}

// asteapta pana cand slave'ul reactioneaza
void twi_wait_transmit(void)
{
    while( (TWCR & (1<<TWINT) ) == 0 ) // TODO - cand este gata interfata - vezi tutorial
	{}
}
 
// porneste transmisia unui byte
void twi_start_transmit(void)
{
    TWCR = (1<<TWINT) | (1<<TWEN); // TODO - vezi tutorial
}


// Functii pentru accesul la memoria EEPROM ///////////////////////////////////
 
// citeste len bytes de la adresa eeaddr si ii pune in buf
int eeprom_read_bytes(uint16_t eeaddr, int len, uint8_t *buf)
{
    uint8_t sla, twcr, n = 0;
    int rv = 0;
    
    // bitii mairi in sla. transmisi tarziu
    sla = SLAVE_ADDRESS | (((eeaddr >> 8) & 0x07) << 1);

restart:
    if( n++ >= MAX_ITER ) 
		return -1;

begin:                      // 1. Trimite start condition
    twi_send_start();
    twi_wait_transmit();
    switch( (twst = TW_STATUS) )               
    {                                         
        case TW_REP_START: 
			break;             
        case TW_START: 
			break;                 
        case TW_MT_ARB_LOST: 
			goto begin;           
        default: 
			return -1;                                      
    }
                            // 2. Trimite adresa memoriei + cerere de scriere
    TWDR = sla | TW_WRITE;
    twi_start_transmit();
    twi_wait_transmit(); 
    switch ((twst = TW_STATUS))               
    {                                         
		case TW_MT_SLA_ACK: 
			break;            
        case TW_MT_SLA_NACK: 
			goto restart;    
        case TW_MT_ARB_LOST: 
			goto begin;      
        default: 
			goto error;		          
    }                            
							// 3. Trimite bitii inferiori ai adresei in memorie
    TWDR = eeaddr;          
    twi_start_transmit();
    twi_wait_transmit() ;
    switch( (twst = TW_STATUS) )
    {
        case TW_MT_DATA_ACK: 
			break;
        case TW_MT_DATA_NACK: 
			goto quit;
        case TW_MT_ARB_LOST: 
			goto begin;
        default: 
			goto error;
    }
                            // 4. Transmite start repetat
    twi_send_rep_start(); 
    twi_wait_transmit();
    switch ((twst = TW_STATUS))
    {
        case TW_START: 
			break;		
        case TW_REP_START: 
			break;
        case TW_MT_ARB_LOST: 
			goto begin;
        default: 
			goto error;
    }
                            // 5. Trimite adresa memorie cu cerere de citire
    TWDR = sla | TW_READ;
    twi_start_transmit();
    twi_wait_transmit();
    switch ((twst = TW_STATUS))
    {
        case TW_MR_SLA_ACK: 
			break;
        case TW_MR_SLA_NACK: 
			goto quit;
        case TW_MR_ARB_LOST: 
			goto begin;
        default: 
			goto error;
    }
                            // 6. Citeste datele
    twcr = _BV(TWINT) | _BV(TWEN) | _BV(TWEA);
    for( ;len > 0;len-- )
    {
        if( len == 1 )
			twcr = _BV(TWINT) | _BV(TWEN); // send nak la sfarsit

        TWCR = twcr;		
        twi_wait_transmit() ; 
        
        switch( (twst = TW_STATUS) )
        {
			case TW_MR_DATA_NACK: 
				len = 0; 
           	case TW_MR_DATA_ACK: 
				*buf++ = TWDR; rv++; 
				break;
           	default: 
				goto error;
	    }
    }
    
quit:
      twi_send_stop();
      return rv;

error:
      rv = -1;
      goto quit;
}


// scrie date din buffer de lungime maxima len, dar fara a iesi
// din limitele unei pagini
int eeprom_write_page( uint16_t eeaddr, int len, uint8_t *buf )
{
    uint8_t sla, n = 0;
    int rv = 0;
    uint16_t endaddr;

    // calculeaza intervalul de adrese pe care le pot scrie
    // astfel incat sa raman in limitele unei pagini
    if( eeaddr + len < ( eeaddr | (PAGE_SIZE - 1 ) ) )
        endaddr = eeaddr + len;
    else
        endaddr = (eeaddr | (PAGE_SIZE - 1)) + 1;
    len = endaddr - eeaddr;

    // pune in sla bitii superiori ai adresei
    sla = SLAVE_ADDRESS | ( ( ( eeaddr >> 8 ) & 0x07 ) << 1 );

restart:
    if( n++ >= MAX_ITER ) 
		return -1;

begin:
                            // 1. Trimite start condition 
    twi_send_start();
    twi_wait_transmit();
    switch( ( twst = TW_STATUS ) )
    {
        case TW_REP_START:
        case TW_START:
			break;
        case TW_MT_ARB_LOST: 
			goto begin;
        default: 
			return -1;  // fara stop condition	
    }
                            // 2. Trimite adresa memoriei + cerere de scriere
    TWDR = sla | TW_WRITE;
    twi_start_transmit();
    twi_wait_transmit();
    switch( (twst = TW_STATUS) )
    {
        case TW_MT_SLA_ACK: 
			break;
        case TW_MT_SLA_NACK: 
			goto restart;
        case TW_MT_ARB_LOST: 
			goto begin;
        default: 
			goto error;		// cu stop condition
    }

    TWDR = eeaddr;          // 3. Trimite 8 biti inferiori ai adresei din mem
    twi_start_transmit();
    twi_wait_transmit();
    switch( (twst = TW_STATUS) )
    {
        case TW_MT_DATA_ACK: 
			break;
        case TW_MT_DATA_NACK: 
			goto quit;
        case TW_MT_ARB_LOST: 
			goto begin;
        default: 
			goto error;
    }
                            // 4. Scrie datele
    for( ; len > 0; len-- )
    {
        TWDR = *buf++;
        twi_start_transmit();
        twi_wait_transmit();
        switch( (twst = TW_STATUS) )
        {
			case TW_MT_DATA_NACK: 
				goto error;
	       	case TW_MT_DATA_ACK: 
				rv++;break;
           	default: 
		   		goto error;
        }
    }

quit:
    twi_send_stop();
    return rv;

error:
    rv = -1;
    goto quit;
}

// scrie un bloc de date de lungime len incepand cu adresa eeaddr
int eeprom_write_bytes( uint16_t eeaddr, int len, uint8_t *buf )
{
    int rv, total;

    total = 0;
    do
    {
        rv = eeprom_write_page(eeaddr, len, buf);
        if( rv == -1 )
			return -1;
      
        eeaddr += rv;
        len -= rv;
        buf += rv;
        total += rv;
    }
    while( len > 0 );

    return total;
}

// Main Function //////////////////////////////////////////////////////////////
int main(void)
{
    char bytes[64];
    int i,j;
	DDRB = 0xFF;

	uart_init();
	twi_init();
  
	printf( "Welcome \n\n" );
    while(1)
    {
        printf( "Enter command: " );
        scanf( "%s",bytes );
        
        if(!strcmp(bytes,"read"))
        {
            for(i=0;i<16;i++)
            {
                eeprom_read_bytes( 16*i, 16, (unsigned char*)bytes );
                for( j=0;j<16;j++ )
                    printf( "%02X ", bytes[j] );
                printf("| ");
                for(j=0;j<16;j++)
                    printf("%c", bytes[j]);
                printf("\n");
            }
        }
        else 
		{
			if(!strcmp(bytes,"write"))
	        {
	            printf( "Enter string to write: " );
	            scanf("%s",bytes);
	            printf( "Enter start address: " );
	            scanf( "%d",&i );
	            eeprom_write_bytes( i, strlen(bytes), (unsigned char*)bytes );
	        }
		  	else 
				printf( "Known commands are 'write' and 'read'\n" );
		}
    }
    
    return 0;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -