modbus documentation done
This commit is contained in:
		
							
								
								
									
										126
									
								
								modbus.c
									
									
									
									
									
								
							
							
						
						
									
										126
									
								
								modbus.c
									
									
									
									
									
								
							| @@ -2,16 +2,16 @@ | ||||
|  * @file modbus.c | ||||
|  * @authors Simon Donnet-Monay & Remi Heredero | ||||
|  * @date 14 march 2023 | ||||
|  * @biref | ||||
|  * @brief  | ||||
|  */ | ||||
|  | ||||
| #include "modbus.h" | ||||
| #include "crc.h" | ||||
|  | ||||
| // Modbus functions | ||||
| #define READ_INPUT_REGISTERS    0x04 //!< Modbus function for read input register = 04 | ||||
| #define READ_HOLDING_REGISTERS  0x03 //!< Modbus function for read holding register = 03 | ||||
| #define WRITE_SINGLE_REGISTER   0x06 //!< Modbus function for write a single register = 06 | ||||
| #define READ_INPUT_REGISTERS    0x04 // Modbus function for read input register | ||||
| #define READ_HOLDING_REGISTERS  0x03 // Modbus function for read holding register | ||||
| #define WRITE_SINGLE_REGISTER   0x06 // Modbus function for write a single register | ||||
|  | ||||
| // Modbus data model | ||||
| uint8_t modbusAddress; | ||||
| @@ -35,45 +35,83 @@ uint8_t tx_buf[256]; | ||||
| // Current position pointer for storing receive position | ||||
| uint8_t recPtr = 0; | ||||
|  | ||||
| /** | ||||
|  * End of MODBUS frame.  | ||||
|  */ | ||||
| void modbus_timer(void) { | ||||
| 	INTCONbits.TMR0IF = 0; | ||||
|     recPtr = 0;    | ||||
|     TMR0_StopTimer(); | ||||
|     modbus_analyse_and_answer(); | ||||
| 	INTCONbits.TMR0IF = 0;          // Reset flag of the timer0 interrupt  | ||||
|     recPtr = 0;                     // Reset position of the char in the frame | ||||
|     TMR0_StopTimer();               // Stop timer who detect the end of the frame | ||||
|     modbus_analyse_and_answer();    // Run analyse of this frame | ||||
| } | ||||
|  | ||||
| extern uint16_t measure_voltage(); | ||||
|  | ||||
| /** | ||||
|  * @brief Analyse the received frame and build an answer | ||||
|  * @return The error code if the frame isn't valid (TODO) | ||||
|  */ | ||||
| uint8_t modbus_analyse_and_answer(void) { | ||||
| 	// TODO -> complete the modbus analyse and answer | ||||
|     // Init lenght of the answer frame at 0 | ||||
|     uint16_t length = 0; | ||||
|      | ||||
|     // Check if the received frame is for this device | ||||
|     if(rx_buf[0] == modbusAddress){ | ||||
|         tx_buf[0] = rx_buf[0]; // Adress | ||||
|         tx_buf[1] = rx_buf[1]; // Function | ||||
|         tx_buf[0] = rx_buf[0];  // Copy the address on the tx buffer | ||||
|         tx_buf[1] = rx_buf[1];  // Copy the function number on the tx buffer | ||||
|          | ||||
|         // Init the addresse Register local variable | ||||
|         uint16_t adresseRegister = ((uint16_t)rx_buf[2] << 8) | rx_buf[3]; | ||||
|          | ||||
|         switch(rx_buf[1]){  // Check the function from rx buffer | ||||
|             case READ_INPUT_REGISTERS: | ||||
|              | ||||
|             // In case of the function is to read input register:  | ||||
|             case READ_INPUT_REGISTERS:  | ||||
|                 // Define length as the number of register we want read | ||||
|                 length = ((uint16_t)rx_buf[4] << 8) | rx_buf[5]; | ||||
|                 tx_buf[2] = (uint8_t)(length*2);        // Data length | ||||
|                  | ||||
|                 // Write this length on the tx buffer for the answer | ||||
|                 tx_buf[2] = (uint8_t)(length*2); | ||||
|                  | ||||
|                 // For each register, write the value on the tx buffer (register on 16bits) | ||||
|                 for(uint16_t i = 0; i < length; i++){   // Data | ||||
|                     tx_buf[i*2+4] = input_registers[adresseRegister+i]; | ||||
|                     tx_buf[i*2+3] = (input_registers[adresseRegister+i] >> 8); | ||||
|                 } | ||||
|                 length*=2; | ||||
|                 length+=3; | ||||
|                  | ||||
|                 // Transform length as the number of bytes on tx register | ||||
|                 length*=2;  // 2 bytes by register | ||||
|                 length+=3;  // + address + function + length | ||||
|                 break; | ||||
|              | ||||
|                  | ||||
|             // In case of the function is to read holding register | ||||
|             case READ_HOLDING_REGISTERS: | ||||
|                 // Define length as the number of register we want read | ||||
|                 length = ((uint16_t)rx_buf[4] << 8) | rx_buf[5]; | ||||
|                 tx_buf[2] = (uint8_t)(length*2);        // Data length | ||||
|                 for(uint16_t i = 0; i < length; i++){   // Data | ||||
|                  | ||||
|                 // Write this length on the tx buffer for the answer | ||||
|                 tx_buf[2] = (uint8_t)(length*2); | ||||
|                  | ||||
|                 // For each register, write the value on the tx buffer (register on 16bits)) | ||||
|                 for(uint16_t i = 0; i < length; i++){ | ||||
|                     tx_buf[i*2+4] = holding_registers[adresseRegister+i]; | ||||
|                     tx_buf[i*2+3] = (holding_registers[adresseRegister+i] >> 8); | ||||
|                 } | ||||
|                 length*=2; | ||||
|                 length+=3; | ||||
|                 // Transform length as the number of bytes on tx register | ||||
|                 length*=2;  // 2 bytes by register | ||||
|                 length+=3;  // + address + function + length | ||||
|                 break; | ||||
|                  | ||||
|              | ||||
|             // In case of the funciton is to write a single register | ||||
|             case WRITE_SINGLE_REGISTER: | ||||
|                  | ||||
|                 // Write the value on rx buffer on the holding register define by the adress register we define before | ||||
|                 holding_registers[adresseRegister] = ((uint16_t)rx_buf[4] << 8) | rx_buf[5]; | ||||
|                 for (int i = 2; i <= 5; i++) { | ||||
|                  | ||||
|                 // Copy data on the tx buffer | ||||
|                 for (uint8_t i = 2; i <= 5; i++) { | ||||
|                     tx_buf[i] = rx_buf[i]; | ||||
|                     length = i+1; | ||||
|                 } | ||||
| @@ -81,39 +119,63 @@ uint8_t modbus_analyse_and_answer(void) { | ||||
|         } | ||||
|          | ||||
|     } | ||||
|         | ||||
|        | ||||
|     // Clear address on rx buffer (for validate we treat the data) | ||||
|     rx_buf[0] = 0; | ||||
|      | ||||
|     // Send the answer frame | ||||
|     modbus_send(length); | ||||
|      | ||||
|     // TODO return error code | ||||
|    | ||||
| } | ||||
|  | ||||
| void modbus_char_recvd(void) | ||||
| { | ||||
| /** | ||||
|  * Record a char when it's received on the modbus | ||||
|  */ | ||||
| void modbus_char_recvd(void) { | ||||
|     //! Record the received char on the rx buffer and move position of the record pointer for the next char | ||||
| 	rx_buf[recPtr++] = RCREG1; | ||||
|      | ||||
|     //! Reload and start the timer0 for restart to count the time between char | ||||
|     TMR0_Reload(); | ||||
|     TMR0_StartTimer(); | ||||
| } | ||||
|  | ||||
| void modbus_send(uint8_t length) | ||||
| { | ||||
|      | ||||
| /** | ||||
|  * Create the CRC and send the tx buffer | ||||
|  * @param length lenght of the frame without the CRC | ||||
|  */ | ||||
| void modbus_send(uint8_t length) { | ||||
|     // Create the CRC | ||||
| 	uint16_t crc = CRC16(tx_buf, length); | ||||
| 	 | ||||
|     // Write CRC on the tx buffer | ||||
|     tx_buf[length] = crc; | ||||
|     tx_buf[length+1] = crc >> 8; | ||||
|  | ||||
| 	length += 2; // add 2 CRC bytes for total size | ||||
| 	length += 2; //! add 2 CRC bytes for total size | ||||
|  | ||||
| 	// For all the bytes to be transmitted | ||||
| 	// Send each byte of the frame on the tx buffer | ||||
|     for (uint8_t i = 0; i < length; i++){ | ||||
|           EUSART1_Write(tx_buf[i]); | ||||
|       } | ||||
| } | ||||
|  | ||||
| void modbus_init(uint8_t address) | ||||
| { | ||||
| 	modbusAddress = address; | ||||
| /** | ||||
|  * Initialize the modbus with adress and handler function | ||||
|  * @param address The adress of this device on modbus protocole | ||||
|  */ | ||||
| void modbus_init(uint8_t address) { | ||||
| 	// Init the modbus adress | ||||
|     modbusAddress = address; | ||||
|      | ||||
|     // Save the modbus adress in the dedicated register | ||||
|     holding_registers[1] = address; | ||||
|      | ||||
|     // Set the handler for the character detection | ||||
|     EUSART1_SetRxInterruptHandler(modbus_char_recvd); | ||||
|      | ||||
|     // Set the handler for the detection of end frame | ||||
|     TMR0_SetInterruptHandler(modbus_timer); | ||||
| } | ||||
| } | ||||
		Reference in New Issue
	
	Block a user