могу предложить ещё и то что на х51 у меня работает верой и правдой не один год ()
(«Телесистемы»: Конференция «Микроконтроллеры и их применение»)

миниатюрный аудио-видеорекордер mAVR

Отправлено Max_Fly 23 июля 2004 г. 10:34
В ответ на: >> Михаил Е. (24С256) отправлено =L.A.= 22 июля 2004 г. 21:35

ассемблерный файл
;****************************************************************************

; Software Implemented I2C Drivers

; These routines allow an 80C51 based microcontroller to drive the I2C bus
; as a single master. The main program at the end demonstrates writing and
; reading several types of devices:

; at24c64

; Written by M.Diatel, JSC "ALAY"

;****************************************************************************


name AsmFunc
public SendData
public RcvData
public SendData_w_Adr
public RcvData_w_Adr

I2C SEGMENT CODE
RSEG I2C
;****************************************************************************
; Definitions
;****************************************************************************


; Addresses of several I2C devices as connected on the Signetics I2C
; Evaluation Board.


extern data (pData);
extern data (AdrDat);Adress bytes for I2C.
extern data (SlvAdr);Slave address for I2C routines.
extern data (ByteCnt);Byte counter for I2C routines.
extern data (BitCnt);Bit counter for I2C routines.

; Data storage locations

extern bit (NoAck);
extern bit (BusFault);
extern bit (I2CBusy);
extern bit (delay);
; I2C connections.

SCLPin BIT P1.5 ;I2C serial clock line.
SDAPin BIT P1.4 ;I2C serial data line.


; BitDly - insures minimum high and low clock times on I2C bus.
; This routine must be tuned for the actual oscilator frequency used, shown
; here tuned for a 12MHz clock. Note that the CALL instruction that invokes
; BitDly already uses 2 machine cycles.

BitDly:
NOP
NOP
NOP ;NOPs to delay 5 microseconds (minus 4
; machine cycles for CALL and RET).
RET


; SCLHigh - sends SCL pin high and waits for any clock stretching peripherals.

SCLHigh: SETB SCLPin ;Set SCL from our end.
JNB SCLPin,$ ;Wait for pin to actually go high.
RET


; SendStop - sends an I2C stop, releasing the bus.

SendStop: CLR SDAPin ;Get SDA ready for stop.
ACALL SCLHigh ;Set clock for stop.
ACALL BitDly
SETB SDAPin ;Send I2C stop.
ACALL BitDly
CLR I2CBusy ;Clear I2C busy status.
RET ;Bus should now be released.


; SendByte - sends one byte of data to an I2C slave device.
; Enter with:
; ACC = data byte to be sent.

SendByte: MOV BitCnt,#8 ;Set bit count.

SBLoop: RLC A ;Send one data bit.
MOV SDAPin,C ;Put data bit on pin.
ACALL SCLHigh ;Send clock.
ACALL BitDly
CLR SCLPin
ACALL BitDly
DJNZ BitCnt,SBloop ;Repeat until all bits sent.

SETB SDAPin ;Release data line for acknowledge.
ACALL SCLHigh ;Send clock for acknowledge.
ACALL BitDly
JNB SDAPin,SBEX ;Check for valid acknowledge bit.
SETB NoAck ;Set status for no acknowledge.
SBEX: CLR SCLPin ;Finish acknowledge bit.
ACALL BitDly
; вставим задержку...
setb EA ; enable all interrupt
nop;
nop;
nop;
clr EA

RET


; GoMaster - sends an I2C start and slave address.
; Enter with:
; SlvAdr = slave address.

GoMaster: SETB I2CBusy ;Indicate that I2C frame is in progress.
CLR NoAck ;Clear error status flags.
CLR BusFault
JNB SCLPin,Fault ;Check for bus clear.
JNB SDAPin,Fault
CLR SDAPin ;Begin I2C start.
ACALL BitDly
CLR SCLPin
ACALL BitDly ;Complete I2C start.
MOV A,SlvAdr ;Get slave address.
ACALL SendByte ;Send slave address.
RET

Fault: SETB BusFault ;Set fault status
RET ; and exit.


; SendData - sends one or more bytes of data to an I2C slave device.
; Enter with:
; ByteCnt = count of bytes to be sent.
; SlvAdr = slave address.
; @pData = data to be sent (the first data byte will be the
; subaddress, if the I2C device expects one).

SendData:
; push R0;
mov R0,pData
ACALL GoMaster ;Acquire bus and send slave address.
JB NoAck,SDEX ;Check for slave not responding.
; push acc ;втолкнуть асс в стек.
SDLoop: MOV acc,@R0 ;Get data byte from buffer.
ACALL SendByte ;Send next data byte.
INC R0 ;Advance buffer pointer.
JB NoAck,SDEX ;Check for slave not responding.
DJNZ ByteCnt,SDLoop ;All bytes sent?
; pop acc
SDEX: ACALL SendStop ;Done, send an I2C stop.
; pop R0;

RET

; SendData - sends one or more bytes of data to an I2C slave device.
; Enter with:
; ByteCnt = count of bytes to be sent.
; SlvAdr = slave address.
; @pData = data to be sent (the first data byte will be the
; subaddress, if the I2C device expects one).
; AdrDat = Adress For New Message.

SendData_w_Adr:
push acc ;втолкнуть асс в стек.
clr EA

SETB NoAck;
ACALL GoMaster ;Acquire bus and send slave address.
JB NoAck,SDEX1 ;Check for slave not responding.

mov R0, AdrDat
MOV acc,@R0 ;записать в аккумулятор адрес начальной ячейки для передачи.
ACALL SendByte ;передать адрес начальной ячейки и получить подтверждение.
JB NoAck,SDEX1 ;если подтверждения нет - закончить сеанс.
inc R0;
MOV acc,@R0 ;записать в аккумулятор адрес начальной ячейки для передачи.
ACALL SendByte ;передать адрес начальной ячейки и получить подтверждение.
JB NoAck,SDEX1 ;если подтверждения нет - закончить сеанс.

mov R0,pData
SDLoop1: MOV acc,@R0 ;Get data byte from buffer.
ACALL SendByte ;Send next data byte.
INC R0 ;Advance buffer pointer.
JB NoAck,SDEX1 ;Check for slave not responding.
DJNZ ByteCnt,SDLoop1 ;All bytes sent?

SDEX1:
pop acc;
ACALL SendStop ;Done, send an I2C stop.
setb EA
RET


;RcvByte - receives one byte of data from an I2C slave device.
; Returns:
; ACC = data byte received.

RcvByte: MOV BitCnt,#8 ;Set bit count.

RBLoop: ACALL SCLHigh ;Read one data bit.
ACALL BitDly
MOV C,SDAPin ;Get data bit from pin.
RLC A ;Rotate bit into result byte.
CLR SCLPin
ACALL BitDly
DJNZ BitCnt,RBLoop ;Repeat until all bits received.

push ACC ;Save accumulator
MOV A,ByteCnt
CJNE A,#1,RBAck ;Check for last byte of frame.
SETB SDAPin ;Send no acknowledge on last byte.
SJMP RBAClk

RBAck: CLR SDAPin ;Send acknowledge bit.
RBAClk: ACALL SCLHigh ;Send acknowledge clock.
pop ACC ;Restore accumulator
ACALL BitDly
CLR SCLPin

; вставим задержку...
setb EA ; enable all interrupt
nop;
nop;
nop;
clr EA

SETB SDAPin ;Clear acknowledge bit.
ACALL BitDly
RET


;RcvData - receives sends one or more bytes of data from an I2C slave device.
; Enter with:
; ByteCnt = count of bytes to be sent.
; SlvAdr = slave address.
; Returns:
; @pData = data received.

; Note: to receive with a subaddress, use SendData to set the subaddress
; first (no provision for repeated start).

RcvData_w_Adr:
; push R0
push acc ;втолкнуть асс в стек.
clr EA
ACALL GoMaster ;Acquire bus and send slave address.
JB NoAck,RDEX1 ;Check for slave not responding.

mov R0, AdrDat
MOV acc,@R0 ;записать в аккумулятор адрес начальной ячейки для передачи.
ACALL SendByte ;передать адрес начальной ячейки и получить подтверждение.
JB NoAck,RDEX1 ;если подтверждения нет - закончить сеанс.
inc R0;
MOV acc,@R0 ;записать в аккумулятор адрес начальной ячейки для передачи.
ACALL SendByte ;передать адрес начальной ячейки и получить подтверждение.
JB NoAck,RDEX1 ;если подтверждения нет - закончить сеанс.

SETB SDAPin;
ACALL SCLHigh;
INC SlvAdr ;Set for READ of slave.
ACALL GoMaster ;Acquire bus and send slave address.
JB NoAck,RDEX1 ;Check for slave not responding.

mov R0,pData
RDLoop1:
ACALL RcvByte ;Recieve next data byte.
MOV @R0,acc ;Save data byte in buffer.
INC R0 ;Advance buffer pointer.
DJNZ ByteCnt,RDLoop1 ;Repeat untill all bytes received.

RDEX1: ACALL SendStop ;Done, send an I2C stop.
pop acc;
setb EA;
RET


;RcvData - receives sends one or more bytes of data from an I2C slave device.
; Enter with:
; ByteCnt = count of bytes to be sent.
; SlvAdr = slave address.
; Returns:
; @R0 = data received.

; Note: to receive with a subaddress, use SendData to set the subaddress
; first (no provision for repeated start).

RcvData: INC SlvAdr ;Set for READ of slave.
ACALL GoMaster ;Acquire bus and send slave address.
JB NoAck,RDEX ;Check for slave not responding.

RDLoop: ACALL RcvByte ;Recieve next data byte.
MOV @R0,A ;Save data byte in buffer.
INC R0 ;Advance buffer pointer.
DJNZ ByteCnt,RDLoop ;Repeat untill all bytes received.

RDEX: ACALL SendStop ;Done, send an I2C stop.
RET


end

С обёртки для ассемблерных вставок


#define EEPROM 0xA0

void Ressive_Data(unsigned char Number,unsigned char Position,int Adress);
void Transmite_Data(unsigned char Number,unsigned char Position,int Adress);
extern void SendData_w_Adr (void);
extern void RcvData_w_Adr (void);

extern data unsigned char* data pData;
extern data unsigned char* pLoading_Byte;
// code unsigned char * data Message;
extern data int* AdrDat;
extern data unsigned char SlvAdr;
extern data unsigned char ByteCnt;
extern data unsigned char BitCnt;
extern data unsigned char XmtDat[32];
extern data unsigned char RcvDat[32];

void Ressive_Data(unsigned char Number,unsigned char Position,int Adress)
{
//пример периёма по I2C
SlvAdr=EEPROM;
ByteCnt=Number;// СКОЛЬКО
pData=(&RcvDat[0]+Position);// Куда это записывать в памяти.
AdrDat=&Adress;// Откуда начинать в EEPROM.
RcvData_w_Adr();
}
void Transmite_Data(unsigned char Number,unsigned char Position,int Adress)
{
//пример передачи по I2C
SlvAdr=EEPROM;
ByteCnt=Number;
pData=(&XmtDat[0]+Position);
AdrDat=&Adress;
SendData_w_Adr();
return;
}
#define EEPROM 0xA0

void Ressive_Data(unsigned char Number,unsigned char Position,int Adress);
void Transmite_Data(unsigned char Number,unsigned char Position,int Adress);
extern void SendData_w_Adr (void);
extern void RcvData_w_Adr (void);

extern data unsigned char* data pData;
extern data unsigned char* pLoading_Byte;
// code unsigned char * data Message;
extern data int* AdrDat;
extern data unsigned char SlvAdr;
extern data unsigned char ByteCnt;
extern data unsigned char BitCnt;
extern data unsigned char XmtDat[32];
extern data unsigned char RcvDat[32];

void Ressive_Data(unsigned char Number,unsigned char Position,int Adress)
{
//пример периёма по I2C
SlvAdr=EEPROM;
ByteCnt=Number;// СКОЛЬКО
pData=(&RcvDat[0]+Position);// Куда это записывать в памяти.
AdrDat=&Adress;// Откуда начинать в EEPROM.
RcvData_w_Adr();
}
void Transmite_Data(unsigned char Number,unsigned char Position,int Adress)
{
//пример передачи по I2C
SlvAdr=EEPROM;
ByteCnt=Number;
pData=(&XmtDat[0]+Position);
AdrDat=&Adress;
SendData_w_Adr();
return;
}


кстати сюда вставлено блокировка прерывания и отпускание в строго нормированные моменты - такая реализация позволяла корректно писать и читать не сбиваясь даже в очень сильно загруженной системе. (Прерывание перехватывает процессор только в дозволенные моменты - и слейв просто ждёт - растягивает циклы. Опыт показал что атмеловские 24сХХ могут растянуть цикл одного бита до 0.5 секунды точно.)(растягиваются циклы просто). заменяли параллельную флешь на подобную еепромину - всё работает вот уже год без претензий.

Составить ответ  |||  Конференция  |||  Архив

Ответы



Перейти к списку ответов  |||  Конференция  |||  Архив  |||  Главная страница  |||  Содержание  |||  Без кадра

E-mail: info@telesys.ru