Сб апр 06, 2019 04:27:52
Вт апр 09, 2019 03:41:26
#include "Macro.h"
/* define baudrate of modbus */
#define MB_ADDR 0x0F
#define BAUD 38400L
#define UBRR ((F_CPU / 8 / BAUD ) -1)
/*
* Use 485 or 232, default: 485
* Use 232 for testing purposes or very simple applications that do not require RS485 and bus topology.
*/
#define PHYSICAL_TYPE 485 //possible values: 485, 232
/*
* Definitions for transceiver enable pin.
*/
#define TRANSCEIVER_ENABLE_PORT PORTD
#define TRANSCEIVER_ENABLE_PIN PD2
#define TRANSCEIVER_ENABLE_PORT_DDR DDRD
/*
* At the moment the user has to set the value for Baudrate and
* speed mode manually. The values depend on the operating frequency
* of your AVR and can be found in its datasheet.
*/
#define USART_TX USART_TX_vect
#define USART_RX USART_RX_vect
#define USART_UDRE USART_UDRE_vect
#define UART_STATUS UCSR0A
#define UART_CONTROL UCSR0B
#define UART_DATA UDR0
#define UART_UDRIE UDRIE0
#define UCSRC UCSR0C
#define RXCIE RXCIE0
#define TXCIE TXCIE0
#define RXEN RXEN0
#define TXEN TXEN0
#define UCSZ0 UCSZ00
#define U2X U2X0
#define UBRRH UBRR0H
#define UBRRL UBRR0L
/*
* Available address modes.
*/
#define MULTIPLE_ADR 2
#define SINGLE_ADR 1
/*
* Use SINGLE_ADR or MULTIPLE_ADR, default: SINGLE_ADR
* This is useful for building gateways, routers or clients that for whatever reason need multiple addresses.
*/
#define ADDRESS_MODE SINGLE_ADR
#define modbusInterFrameDelayReceiveStart 16
#define modbusInterFrameDelayReceiveEnd 18
#define modbusInterCharTimeout 7
/**
* @brief Defines the maximum Modbus frame size accepted by the device. 255 is the default
* and also the maximum value. However, it might be useful to set this to lower
* values, with 8 being the lowest possible value, in order to save on ram space.
*/
#define MaxFrameIndex 255
/**
* Modbus Function Codes
* Refer to modbus.org for further information.
* It's good practice to return exception code 01 in case you receive a function code
* that you haven't implemented in your application.
*/
#define fcReadCoilStatus 1 //read single/multiple coils
#define fcReadInputStatus 2 //read single/multiple inputs
#define fcReadHoldingRegisters 3 //read analog output registers
#define fcReadInputRegisters 4 //read analog input registers (2 Bytes per register)
#define fcForceSingleCoil 5 //write single bit
#define fcPresetSingleRegister 6 //write analog output register (2 Bytes)
#define fcForceMultipleCoils 15 //write multiple bits
#define fcPresetMultipleRegisters 16 //write multiple analog output registers (2 Bytes each)
#define fcReportSlaveID 17 //read device description, run status and other device specific information
/*
* Modbus Exception Codes
* Refer to modbus.org for further information.
* It's good practice to return exception code 01 in case you receive a function code
* that you haven't implemented in your application.
*/
#define ecIllegalFunction 1
#define ecIllegalDataAddress 2
#define ecIllegalDataValue 3
#define ecSlaveDeviceFailure 4
#define ecAcknowledge 5
#define ecSlaveDeviceBusy 6
#define ecNegativeAcknowledge 7
#define ecMemoryParityError 8
/**
* @brief Internal bit definitions
*/
#define BusTimedOut 0
#define Receiving 1
#define Transmitting 2
#define ReceiveCompleted 3
#define TransmitRequested 4
#define TimerActive 5
#define GapDetected 6
/**
* @brief Configures the UART. Call this function only once.
*/
extern void modbusInit(void);
/**
* @brief receive/transmit data array
*/
extern volatile uint8_t rxbuffer[MaxFrameIndex+1];
/**
* @brief Current receive/transmit position
*/
extern volatile uint16_t DataPos;
/**
* This only applies to single address mode.
*/
#if ADDRESS_MODE == SINGLE_ADR
/**
* @brief: Read the device address
*/
extern uint8_t modbusGetAddress(void);
/**
* @brief: Set the device address
* Arguments: - newadr: the new device address
*/
extern void modbusSetAddress(uint8_t newadr);
#endif
/* @brief: Sends a response.
*
* Arguments: - packtop, index of the last byte in rxbuffer
* that contains payload. Maximum value is
* MaxFrameIndex-2.
*/
extern void modbusSendMessage(uint8_t packtop);
/* @brief: Sends a Modbus exception.
*
* Arguments: - exceptionCode
*/
extern void modbusSendException(uint8_t exceptionCode);
/* @brief: Discards the current transaction. For MULTIPLE_ADR-mode and general
* testing purposes. Call this function if you don't want to reply at all.
*/
void modbusReset(void);
/**
* @brief Call this function whenever possible and check if its return value has the ReceiveCompleted Bit set.
* Preferably do this in the main while. I do not recommend calling this function within ISRs.
* @example if (modbusGetBusState() & (1<<ReceiveCompleted)) {
* modbusSendExcepton(ecIllegalFunction);
* }
*/
extern uint8_t modbusGetBusState(void);
/**
* @brief Call every 100us using a timer ISR.
*/
extern void modbusTickTimer(void);
/**
* @brief Returns amount of bits/registers requested.
*/
extern uint16_t modbusRequestedAmount(void);
/**
* @brief Returns the address of the first requested bit/register.
*/
extern uint16_t modbusRequestedAddress(void);
/* A fairly simple and hopefully Modbus compliant 16 Bit CRC algorithm.
* Returns 1 if the crc check is positive, returns 0 if it fails.
* Appends two crc bytes to the array.
*/
extern uint8_t crc16(volatile uint8_t *ptrToArray,uint8_t inputSize);
/* @brief: Handles single/multiple input/coil reading and single/multiple coil writing.
*
* Arguments: - ptrToInArray: pointer to the user's data array containing bits
* - startAddress: address of the first bit in the supplied array
* - size: input array size in the requested format (bits)
*
*/
extern uint8_t modbusExchangeBits(volatile uint8_t *ptrToInArray, uint16_t startAddress, uint16_t size);
/* @brief: Handles single/multiple register reading and single/multiple register writing.
*
* Arguments: - ptrToInArray: pointer to the user's data array containing registers
* - startAddress: address of the first register in the supplied array
* - size: input array size in the requested format (16bit-registers)
*
*/
extern uint8_t modbusExchangeRegisters(volatile uint16_t *ptrToInArray, uint16_t startAddress, uint16_t size);
#include <avr/io.h>
#include <avr/interrupt.h>
#include "ModBusSlave.h"
#include "Macro.h"
volatile uint8_t BusState = 0;
volatile uint16_t modbusTimer = 0;
volatile uint8_t rxbuffer[MaxFrameIndex+1];
volatile uint16_t DataPos = 0;
volatile uint8_t PacketTopIndex = 7;
volatile uint8_t modBusStaMaStates = 0;
uint8_t modbusGetBusState(void)
{
return BusState;
}
#if ADDRESS_MODE == SINGLE_ADR
volatile uint8_t Address = 0x00;
uint8_t modbusGetAddress(void)
{
return Address;
}
void modbusSetAddress(uint8_t newadr)
{
Address = newadr;
}
#endif
#if PHYSICAL_TYPE == 485
void transceiver_txen(void)
{
TRANSCEIVER_ENABLE_PORT|=(1<<TRANSCEIVER_ENABLE_PIN);
}
void transceiver_rxen(void)
{
TRANSCEIVER_ENABLE_PORT&=~(1<<TRANSCEIVER_ENABLE_PIN);
}
#endif
/* @brief: A fairly simple Modbus compliant 16 Bit CRC algorithm.
*
* Returns 1 if the crc check is positive, returns 0 and saves the calculated CRC bytes
* at the end of the data array if it fails.
*
*/
uint8_t crc16(volatile uint8_t *ptrToArray,uint8_t inputSize) //A standard CRC algorithm
{
uint16_t out=0xffff;
uint16_t carry;
uint8_t n;
inputSize++;
for (int l=0; l<inputSize; l++) {
out ^= ptrToArray[l];
for (n = 0; n < 8; n++) {
carry = out & 1;
out >>= 1;
if (carry) out ^= 0xA001;
}
}
//out=0x1234;
if ((ptrToArray[inputSize]==out%256) && (ptrToArray[inputSize+1]==out/256)) //check
{
return 1;
} else {
ptrToArray[inputSize]=out%256; //append Lo
ptrToArray[inputSize+1]=out/256; //append Hi
return 0;
}
}
/* @brief: copies a single or multiple words from one array of bytes to another array of bytes
* amount must not be bigger than 255...
*
*/
void listRegisterCopy(volatile uint8_t *source, volatile uint8_t *target, uint8_t amount)
{
for (uint8_t c=0; c<amount; c++)
{
*(target+c)=*(source+c);
}
}
/* @brief: copies a single bit from one char to another char (or arrays thereof)
*
*
*/
void listBitCopy(volatile uint8_t *source, uint16_t sourceNr,volatile uint8_t *target, uint16_t targetNr)
{
if(*(source+(sourceNr/8))&(1<<(sourceNr-((sourceNr/8)*8))))
{
*(target+(targetNr/8))|=(1<<(targetNr-((targetNr/8)*8)));
} else *(target+(targetNr/8))&=~(1<<(targetNr-((targetNr/8)*8)));
}
/* @brief: Back to receiving state.
*
*/
void modbusReset(void)
{
BusState=(1<<TimerActive); //stop receiving (error)
modbusTimer=0;
}
void modbusTickTimer(void)
{
if (BusState&(1<<TimerActive))
{
modbusTimer++;
if (BusState&(1<<Receiving)) //we are in receiving mode
{
if ((modbusTimer==modbusInterCharTimeout)) {
BusState|=(1<<GapDetected);
} else if ((modbusTimer==modbusInterFrameDelayReceiveEnd)) { //end of message
BusState=(1<<ReceiveCompleted);
#if ADDRESS_MODE == MULTIPLE_ADR
if (crc16(rxbuffer,DataPos-3)) { //perform crc check only. This is for multiple/all address mode.
} else modbusReset();
#endif
#if ADDRESS_MODE == SINGLE_ADR
if (rxbuffer[0]==Address && crc16(rxbuffer,DataPos-3)) { //is the message for us? => perform crc check
} else modbusReset();
#endif
}
} else if (modbusTimer==modbusInterFrameDelayReceiveStart) BusState|=(1<<BusTimedOut);
}
}
ISR(USART_RX)
{
uint8_t data;
data = UART_DATA;
modbusTimer=0; //reset timer
if (!(BusState & (1<<ReceiveCompleted)) && !(BusState & (1<<TransmitRequested)) && !(BusState & (1<<Transmitting)) && (BusState & (1<<Receiving)) && !(BusState & (1<<BusTimedOut)))
{
if (DataPos>MaxFrameIndex) modbusReset();
else
{
rxbuffer[DataPos]=data;
DataPos++; //TODO: maybe prevent this from exceeding 255?
}
} else
if (!(BusState & (1<<ReceiveCompleted)) && !(BusState & (1<<TransmitRequested)) && !(BusState & (1<<Transmitting)) && !(BusState & (1<<Receiving)) && (BusState & (1<<BusTimedOut)))
{
rxbuffer[0]=data;
BusState=((1<<Receiving)|(1<<TimerActive));
DataPos=1;
}
}
ISR(USART_UDRE)
{
BusState&=~(1<<TransmitRequested);
BusState|=(1<<Transmitting);
UART_DATA=rxbuffer[DataPos];
DataPos++;
if (DataPos==(uint8_t)(PacketTopIndex+1)) {
UART_CONTROL&=~(1<<UART_UDRIE);
}
}
ISR(USART_TX)
{
#if PHYSICAL_TYPE == 485
transceiver_rxen();
#endif
modbusReset();
}
void modbusInit(void)
{
UBRRH = (uint8_t)((UBRR) >> 8);
UBRRL = (uint8_t) UBRR;
UART_STATUS = (1<<U2X); //double speed mode.
#ifdef URSEL // if UBRRH and UCSRC share the same I/O location , e.g. ATmega8
UCSRC = (1<<URSEL)|(3<<UCSZ0); //Frame Size
#else
UCSRC = (3<<UCSZ0); //Frame Size
#endif
UART_CONTROL = (1<<TXCIE)|(1<<RXCIE)|(1<<RXEN)|(1<<TXEN); // USART receiver and transmitter and receive complete interrupt
#if PHYSICAL_TYPE == 485
TRANSCEIVER_ENABLE_PORT_DDR|=(1<<TRANSCEIVER_ENABLE_PIN);
transceiver_rxen();
#endif
BusState=(1<<TimerActive);
}
/* @brief: Sends a response.
*
* Arguments: - packtop: Position of the last byte containing data.
* modbusSendException is a good usage example.
*/
void modbusSendMessage(uint8_t packtop)
{
PacketTopIndex=packtop+2;
crc16(rxbuffer,packtop);
BusState|=(1<<TransmitRequested);
DataPos=0;
#if PHYSICAL_TYPE == 485
transceiver_txen();
#endif
UART_CONTROL|=(1<<UART_UDRIE);
BusState&=~(1<<ReceiveCompleted);
}
/* @brief: Sends an exception response.
*
* Arguments: - exceptionCode
*
*/
void modbusSendException(uint8_t exceptionCode)
{
rxbuffer[1]|=(1<<7); //setting MSB of the function code (the exception flag)
rxbuffer[2]=exceptionCode; //Exceptioncode. Also the last byte containing data
modbusSendMessage(2);
}
/* @brief: Returns the amount of requested data objects (coils, discretes, registers)
*
*/
uint16_t modbusRequestedAmount(void)
{
return (rxbuffer[5]|(rxbuffer[4]<<8));
}
/* @brief: Returns the address of the first requested data object (coils, discretes, registers)
*
*/
uint16_t modbusRequestedAddress(void)
{
return (rxbuffer[3]|(rxbuffer[2]<<8));
}
/* @brief: copies a single or multiple bytes from one array of bytes to an array of 16-bit-words
*
*/
void intToModbusRegister(volatile uint16_t *inreg, volatile uint8_t *outreg, uint8_t amount)
{
for (uint8_t c=0; c<amount; c++)
{
*(outreg+c*2) = (uint8_t)(*(inreg+c) >> 8);
*(outreg+1+c*2) = (uint8_t)(*(inreg+c));
}
}
/* @brief: copies a single or multiple 16-bit-words from one array of integers to an array of bytes
*
*/
void modbusRegisterToInt(volatile uint8_t *inreg, volatile uint16_t *outreg, uint8_t amount)
{
for (uint8_t c=0; c<amount; c++)
{
*(outreg+c) = (*(inreg+c*2) << 8) + *(inreg+1+c*2);
}
}
/* @brief: Handles single/multiple register reading and single/multiple register writing.
*
* Arguments: - ptrToInArray: pointer to the user's data array containing registers
* - startAddress: address of the first register in the supplied array
* - size: input array size in the requested format (16bit-registers)
*
*/
uint8_t modbusExchangeRegisters(volatile uint16_t *ptrToInArray, uint16_t startAddress, uint16_t size)
{
uint16_t requestedAmount = modbusRequestedAmount();
uint16_t requestedAdr = modbusRequestedAddress();
if (rxbuffer[1]==fcPresetSingleRegister) requestedAmount=1;
if ((requestedAdr>=startAddress) && ((startAddress+size)>=(requestedAmount+requestedAdr))) {
if ((rxbuffer[1]==fcReadHoldingRegisters) || (rxbuffer[1]==fcReadInputRegisters) )
{
if ((requestedAmount*2)<=(MaxFrameIndex-4)) //message buffer big enough?
{
rxbuffer[2]=(uint8_t)(requestedAmount*2);
intToModbusRegister(ptrToInArray+(uint8_t)(requestedAdr-startAddress),rxbuffer+3,requestedAmount);
modbusSendMessage(2+rxbuffer[2]);
return 1;
} else modbusSendException(ecIllegalDataValue);
}
else if (rxbuffer[1]==fcPresetMultipleRegisters)
{
if (((rxbuffer[6])>=requestedAmount*2) && ((DataPos-9)>=rxbuffer[6])) //enough data received?
{
modbusRegisterToInt(rxbuffer+7,ptrToInArray+(uint8_t)(requestedAdr-startAddress),(uint8_t)(requestedAmount));
modbusSendMessage(5);
return 1;
} else modbusSendException(ecIllegalDataValue);//too few data bytes received
}
else if (rxbuffer[1]==fcPresetSingleRegister)
{
modbusRegisterToInt(rxbuffer+4,ptrToInArray+(uint8_t)(requestedAdr-startAddress),1);
modbusSendMessage(5);
return 1;
}
//modbusSendException(ecSlaveDeviceFailure); //inapropriate call of modbusExchangeRegisters
return 0;
} else {
modbusSendException(ecIllegalDataValue);
return 0;
}
}
/* @brief: Handles single/multiple input/coil reading and single/multiple coil writing.
*
* Arguments: - ptrToInArray: pointer to the user's data array containing bits
* - startAddress: address of the first bit in the supplied array
* - size: input array size in the requested format (bits)
*
*/
uint8_t modbusExchangeBits(volatile uint8_t *ptrToInArray, uint16_t startAddress, uint16_t size)
{
uint16_t requestedAmount = modbusRequestedAmount();
uint16_t requestedAdr = modbusRequestedAddress();
if (rxbuffer[1]==fcForceSingleCoil) requestedAmount=1;
if ((requestedAdr>=startAddress) && ((startAddress+size)>=(requestedAmount+requestedAdr)))
{
if ((rxbuffer[1]==fcReadInputStatus) || (rxbuffer[1]==fcReadCoilStatus))
{
if (requestedAmount<=((MaxFrameIndex-4)*8)) //message buffer big enough?
{
rxbuffer[2]=(requestedAmount/8);
if (requestedAmount%8>0)
{
rxbuffer[(uint8_t)(requestedAmount/8)+3]=0x00; //fill last data byte with zeros
rxbuffer[2]++;
}
for (uint16_t c = 0; c<requestedAmount; c++)
{
listBitCopy(ptrToInArray,requestedAdr-startAddress+c,rxbuffer+3,c);
}
modbusSendMessage(rxbuffer[2]+2);
return 1;
} else modbusSendException(ecIllegalDataValue); //too many bits requested within single request
}
else if (rxbuffer[1]==fcForceMultipleCoils)
{
if (((rxbuffer[6]*8)>=requestedAmount) && ((DataPos-9)>=rxbuffer[6])) //enough data received?
{
for (uint16_t c = 0; c<requestedAmount; c++)
{
listBitCopy(rxbuffer+7,c,ptrToInArray,requestedAdr-startAddress+c);
}
modbusSendMessage(5);
return 1;
} else modbusSendException(ecIllegalDataValue);//exception too few data bytes received
}
else if (rxbuffer[1]==fcForceSingleCoil) {
listBitCopy(rxbuffer+4,0,ptrToInArray,requestedAdr-startAddress);
modbusSendMessage(5);
return 1;
}
//modbusSendException(ecSlaveDeviceFailure); //inanpropriate call of modbusExchangeBits
return 0;
} else
{
modbusSendException(ecIllegalDataValue);
return 0;
}
}
/*************************Реализация TWI режим Slave***************************/
#define F_CPU 20000000UL
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/atomic.h>
#include <string.h>
#include <util/delay.h>
#include "IIC_ultimate.h"
#include "ModBusSlave.h"
#include "Macro.h"
/*****************************Global Variables*********************************/
struct Data {
volatile uint8_t InState[5]; //Дискретные входа
volatile uint8_t OutState[5]; //Дискретные выхода
volatile uint16_t InputRegisters[4]; //Выходные 16-Битные данные.
volatile uint16_t HoldingRegisters[4]; //Входные 16-Битные данные.
} DataBus;
uint8_t CpyComplete=0;
/***********************************TWI****************************************/
void SlaveControl(void);
void TWI_MasterRequest();
void TWI_MasterRequestComplete();
void TWI_MasterTransmit();
void TWI_MasterTransmitComplete();
void FillBufferTransmit();
/**********************************MODBUS**************************************/
void InitTimer0(void);
void modbusGet(void);
uint8_t CpyModbusToTWI(void);
ISR(TIMER0_OVF_vect)
{
modbusTickTimer();
}
int main()
{
Init_i2c(); //Мастер режим
Init_Slave_i2c(&SlaveControl); //Слейв режим
modbusSetAddress(MB_ADDR);
modbusInit();
InitTimer0();
sei();
DDRB|=(1<<2)|(1<<3);
while(1)
{
if (BIT_IS_SET(DataBus.OutState[0],0))
{
SET_BIT(PORTB,2);
}else
{
CLR_BIT(PORTB,2);
}
if (BIT_IS_SET(DataBus.OutState[0],1))
{
SET_BIT(PORTB,3);
}else
{
CLR_BIT(PORTB,3);
}
modbusGet();
}
return 0;
}
void InitTimer0(void) {
SET_BIT(TCCR0B, CS01);
SET_BIT(TIMSK0, TOIE0);
}
void modbusGet(void) {
if (modbusGetBusState() & (1 << ReceiveCompleted)) {
switch (rxbuffer[1]) {
case fcReadCoilStatus: {
modbusExchangeBits(DataBus.OutState, 0,sizeof(DataBus.OutState));
//CpyModbusToTWI();
} break;
case fcReadInputStatus: {
modbusExchangeBits(DataBus.InState, 0,sizeof(DataBus.InState));
//CpyModbusToTWI();
} break;
case fcReadHoldingRegisters: {
modbusExchangeRegisters(DataBus.HoldingRegisters, 0,sizeof(DataBus.HoldingRegisters));
//CpyModbusToTWI();
} break;
case fcReadInputRegisters: {
modbusExchangeRegisters(DataBus.InputRegisters, 0,sizeof(DataBus.InputRegisters));
//CpyModbusToTWI();
} break;
case fcForceSingleCoil: {
modbusExchangeBits(DataBus.OutState, 0,sizeof(DataBus.OutState));
//CpyModbusToTWI();
} break;
case fcPresetSingleRegister: {
modbusExchangeRegisters(DataBus.HoldingRegisters,0,sizeof(DataBus.HoldingRegisters));
CpyModbusToTWI();
TWI_MasterTransmit();
} break;
case fcForceMultipleCoils: {
modbusExchangeBits(DataBus.OutState, 0,sizeof(DataBus.OutState));
//CpyModbusToTWI();
} break;
case fcPresetMultipleRegisters: {
modbusExchangeRegisters(DataBus.HoldingRegisters,0,sizeof(DataBus.HoldingRegisters));
CpyModbusToTWI();
TWI_MasterTransmit();
} break;
default: {
modbusSendException(ecIllegalFunction);
} break;
}
}
}
void FillBufferTransmit()
{
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
memcpy((i2c_Buffer), &DataBus, (sizeof(DataBus)));
}
return;
}
uint8_t CpyModbusToTWI()
{
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
memcpy((i2c_OutBuff), &DataBus, (sizeof(DataBus)));
CpyComplete=1;
}
return 1;
}
void TWI_MasterRequest()
{
//Если шина занята, то выход из функции
if (i2c_Do & i2c_Busy)
{
return;
}
i2c_index=0; //Обнуляем индекс.
i2c_ByteCount=26; //Устанавливаем размер пакета
i2c_SlaveAddress=0x32; //Адресс слейва
i2c_Do=i2c_sarp; //Режим чтения
MasterOutFunc=&TWI_MasterRequestComplete;
ErrorOutFunc=&TWI_MasterRequestComplete;
TWCR = 1<<TWSTA|0<<TWSTO|1<<TWINT|0<<TWEA|1<<TWEN|1<<TWIE;
i2c_Do |= i2c_Busy; //Занимаем шину.
}
void TWI_MasterRequestComplete()
{
i2c_Do &=i2c_Free; //Освободить шину
//Если был сбой, или слейв нас не услышал.
if (i2c_Do &(i2c_ERR_BF | i2c_ERR_NA))
{
TWI_MasterRequest(); //Повторить попытку считывания данных.
return;
}
}
void TWI_MasterTransmit()
{
//Если передатчик занят , то выход из функции.
if (i2c_Do & i2c_Busy)
{
return;
}
i2c_index=0; //Обнуляем индекс
i2c_ByteCount=26; //Размер пакета
i2c_SlaveAddress=0x32; //Адрес слейва
FillBufferTransmit(); //Заполнение массива передачи.
i2c_Do=i2c_sawp; //Режим простой заиси.
MasterOutFunc=&TWI_MasterTransmitComplete;
ErrorOutFunc=&TWI_MasterTransmitComplete;
TWCR = 1<<TWSTA|0<<TWSTO|1<<TWINT|0<<TWEA|1<<TWEN|1<<TWIE;
i2c_Do |= i2c_Busy; //Занимаем шину.
}
void TWI_MasterTransmitComplete()
{
i2c_Do &= i2c_Free; //Освобождаем шину
//Если был сбой, или адрес нас не услышал.
if (i2c_Do & (i2c_ERR_BF | i2c_ERR_NA))
{
TWI_MasterTransmit(); //Повторить передачу.
return;
}
}
void SlaveControl(void)
{
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
memcpy(&DataBus,i2c_InBuff,(sizeof(DataBus)));
DataBus.HoldingRegisters[0]*=10;
DataBus.HoldingRegisters[1]*=10;
DataBus.HoldingRegisters[2]*=10;
DataBus.HoldingRegisters[3]*=10;
CpyComplete=1;
}
CpyComplete=0;
i2c_Do &= i2c_Free; //Освобождаем шину
}
Ср апр 10, 2019 17:32:10
Вс май 26, 2019 16:26:34
Вт ноя 12, 2019 05:57:31
Ср ноя 20, 2019 14:14:15
Чт ноя 21, 2019 08:18:29
Чт ноя 21, 2019 09:18:04
Чт ноя 21, 2019 09:44:13
Пт ноя 22, 2019 04:56:02
PortName := "COM1";
ComPort1->Port := PortName;
Пт ноя 22, 2019 07:33:17
Вс ноя 24, 2019 03:57:03
Вс ноя 24, 2019 14:40:51
Пн ноя 25, 2019 14:35:39
Пн ноя 25, 2019 16:49:43