You are on page 1of 4

#include #include #include #include

<avr/io.h> <avr/interrupt.h> <stdint.h> "ModbusRTU.h"

volatile uint8_t INTER_CHARACTER_TIMER_CYCLES; volatile uint8_t INTER_FRAME_TIMER_CYCLES; volatile uint8_t BASE_TIMER_CONST; volatile volatile volatile volatile volatile volatile volatile volatile volatile uint8_t uint8_t uint8_t uint8_t uint8_t uint8_t uint8_t uint8_t uint8_t frameStage; modbusRxBuffer[MODBUS_RX_BUFFER_SIZE]; modbusTxBuffer[MODBUS_TX_BUFFER_SIZE]; modbusRxBufferIndex; modbusTxBufferIndex; isrTxBufferIndex; modbusDiagnostic[8]; MODBUS_ADDRESS; timer_cycles;

ISR(USART_RXC_vect){ timer_cycles = 0; TCNT0 = BASE_TIMER_CONST; TIFR |= _BV(TOV0); // clear interrupt flag TCCR0 = 1; // timer start uint8_t status = UCSRA; uint8_t data = UDR; if(frameStage & FRAME_END){ frameStage = FRAME_END_ERROR; return; } if(status & _BV(DOR)){ modbusDiagnostic[7]++; frameStage = FRAME_END_ERROR; return; } if(status & _BV(FE)){ modbusDiagnostic[1]++; frameStage = FRAME_END_ERROR; return; } if(frameStage == FRAME_IDLE){ modbusRxBuffer[0] = data; modbusRxBufferIndex = 1; frameStage = FRAME_DATA; return; } if(frameStage == FRAME_DATA){ modbusRxBuffer[modbusRxBufferIndex++] = data; return; } } uint16_t modbusCRC16(uint8_t * data, uint8_t size){ uint8_t i,n; uint16_t crc = 0xffff; for(i = 0; i size; i++){ crc ^= data[i]; for(n = 0; n 8; n++)

crc = (crc & 0x0001)?((crc >> 1)^0xa001):(crc >> 1); } return crc; } uint8_t modbusCRCCheck(void){ uint16_t crc16 = modbusCRC16(modbusRxBuffer,modbusRxBufferIndex-2); if((uint8_t)crc16 == modbusRxBuffer[modbusRxBufferIndex-2]) if((uint8_t)(crc16 >> 8) == modbusRxBuffer[modbusRxBufferIndex-1]) return 1; return 0; } void fillException(uint8_t code){ modbusTxBuffer[1] = modbusRxBuffer[1] | 0x80; modbusTxBuffer[2] = code; modbusTxBufferIndex = 3; modbusDiagnostic[2]++; } void modbusProcessBroadcast(void){} void modbusProcessUnicast(void){ uint8_t dataBlockSize = modbusRxBufferIndex-4; uint8_t i; modbusTxBuffer[0] = MODBUS_ADDRESS; if(modbusRxBuffer[1] == 0x08){ //Diagnostic function if(dataBlockSize 2){ //length incorrect fillException(0x03); return; } // modbusRxBuffer[2] should be '0x00' in this case switch(modbusRxBuffer[3]){ case 0x00:{ // echo subfunction for(i = 1; i modbusRxBufferIndex-2; i++) modbusTxBuffer[i] = modbusRxBuffer[i]; modbusTxBufferIndex = modbusRxBufferIndex-2; break; } default:{ // subfunction code is not supported fillException(0x01); return; } } return; } if(modbusRxBuffer[1] == 0x06){ //Write single register function if(dataBlockSize 4){ // length incorrect fillException(0x03); return; } uint8_t exc = modbusServerWriteSingleRegister(modbusRxBuffer[3],modbusRxBuff er[5]); if(exc){ fillException(exc); return; } for(i = 1; i modbusRxBufferIndex-2 ; i++)

modbusTxBuffer[i] = modbusRxBuffer[i]; modbusTxBufferIndex = modbusRxBufferIndex-2; return; } if(modbusRxBuffer[1] == 0x04){//read multiple registers function if(dataBlockSize 4){ //length incorrect fillException(0x03); return; } //modbusRxBuffer[5] - quantity uint8_t exc = modbusServerReadMultipleRegisters(modbusRxBuffer[3],modbusRxBu ffer[5],modbusTxBuffer); if(exc){ fillException(exc); return; } modbusTxBuffer[1] = 0x04; modbusTxBuffer[2] = modbusRxBuffer[5]*2; modbusTxBufferIndex = 3 + modbusRxBuffer[5]*2; return; } fillException(0x01); // function code is not supported } void modbusProcessFrame(void){ //uartTx(modbusRxBufferIndex); if(modbusRxBufferIndex 4){ modbusDiagnostic[1]++; return; } if(!modbusCRCCheck()){ modbusDiagnostic[1]++; return; } modbusDiagnostic[0]++; if((modbusRxBuffer[0] == 0) || (modbusRxBuffer[0] == MODBUS_ADDRESS)){ modbusDiagnostic[3]++; if(modbusRxBuffer[0] == 0){ modbusDiagnostic[4]++; modbusProcessBroadcast(); } else modbusProcessUnicast(); uint16_t crc = modbusCRC16(modbusTxBuffer, modbusTxBufferIndex); modbusTxBuffer[modbusTxBufferIndex++] = (uint8_t)crc; modbusTxBuffer[modbusTxBufferIndex++] = (uint8_t)(crc >> 8); //isrTxBufferIndex = 0; //UCSRA &= ~_BV(TXC); //software interrupt to start transmission isrTxBufferIndex = 1; UDR = modbusTxBuffer[0]; return; } } ISR(TIMER0_OVF_vect){ timer_cycles++; if(timer_cycles == INTER_CHARACTER_TIMER_CYCLES){ if(frameStage != FRAME_END_ERROR){

frameStage = FRAME_END; } } if(timer_cycles == INTER_FRAME_TIMER_CYCLES){ TCCR0 = 0; //timer stop if(frameStage == FRAME_END){ UCSRB &= ~_BV(RXEN); //disable UART RX UCSRA |= _BV(RXC); //for _rx_complete_ interrupts not to come - that may w aste rxBuffer sei(); // enabling interrupts -- ADC conversions will not be delayed when fr ame is processed modbusProcessFrame(); UCSRA |= _BV(RXC); //clear reception complete flag UCSRB |= _BV(RXEN); //enable UART RX } if(frameStage == FRAME_END_ERROR) modbusDiagnostic[1]++; frameStage = FRAME_IDLE; TCCR0 = 0; // stop this timer till next RX } TCNT0 = BASE_TIMER_CONST; } ISR(USART_TXC_vect){ if(isrTxBufferIndex == modbusTxBufferIndex) return; UDR = modbusTxBuffer[isrTxBufferIndex++]; } void modbusInit(uint32_t f_cpu, uint32_t uart_speed, uint8_t modbus_address){ //uart init UBRRH = (unsigned char)(UART_BAUD_SELECT(uart_speed,f_cpu) >> 8); UBRRL = (unsigned char) UART_BAUD_SELECT(uart_speed,f_cpu); //enable Rx and Tx; enable Rx interrupt UCSRB = _BV(RXEN)|_BV(TXEN)|_BV(RXCIE)|_BV(TXCIE); /* Set frame format: asynchronous, 8data, parity none, 2stop bits */ UCSRC = _BV(URSEL)|_BV(USBS)|_BV(UCSZ0)|_BV(UCSZ1); UCSRA |= _BV(TXC); //clear transmission complete flag UCSRA |= _BV(RXC); //clear reception complete flag MODBUS_ADDRESS = modbus_address; //timer init TIMSK |= _BV(TOIE0); //enabling timer interrupt TCCR0 = 0x00; //timer stop // inter-character delay = 750us; inter-frame delay = 1.750ms; BASE_TIMER_CONST = (f_cpu/100000UL); //10us*(f_cpu/1000000) INTER_CHARACTER_TIMER_CYCLES = 75; INTER_FRAME_TIMER_CYCLES = 175; //fill modbusDiagnostic with zeros frameStage = FRAME_IDLE; modbusRxBufferIndex = 0; modbusTxBufferIndex = 0; isrTxBufferIndex = 0; timer_cycles = 0; }

You might also like