📄 lab5.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 + -