fix reveiced and decode data

This commit is contained in:
King Kévin 2016-09-14 10:02:38 +02:00
parent 9b047ccf41
commit f0eb5e0f7c
2 changed files with 61 additions and 56 deletions

View File

@ -49,10 +49,9 @@
/* input and output ring buffer, indexes, and available memory */
static uint8_t rx_buffer[9] = {0}; /**< buffer for received response (ModBus response messages can be 2+256+2 long but we will only read up to 2 registers) */
static volatile uint8_t rx_i = 0; /**< current position of read received data */
static volatile uint8_t rx_used = 0; /**< number of received data bytes in buffer */
static uint8_t tx_buffer[13] = {0}; /**< buffer for request to transmit (ModBus request messages can be 7+256+2 long but we will only write up to 2 registers */
static volatile uint8_t tx_i = 0; /**< current position of transmitted data */
static volatile uint8_t tx_size = 0; /**< size of data to transmitted */
static volatile uint8_t tx_used = 0; /**< number of byte to transmit */
volatile bool sensor_sdm120_measurement_received = false;
@ -103,7 +102,7 @@ void sensor_sdm120_setup(void)
rcc_periph_clock_enable(USART_RCC(SENSOR_SDM120_USART)); // enable clock for USART peripheral
gpio_set_mode(USART_PORT(SENSOR_SDM120_USART), GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, USART_PIN_TX(SENSOR_SDM120_USART)); // setup GPIO pin USART transmit
gpio_set_mode(USART_PORT(SENSOR_SDM120_USART), GPIO_MODE_INPUT, GPIO_CNF_INPUT_PULL_UPDOWN, USART_PIN_RX(SENSOR_SDM120_USART)); // setup GPIO pin USART receive
gpio_set(USART_PORT(SENSOR_SDM120_USART), USART_PIN_RX(SENSOR_SDM120_USART)); // pull up to avoid noise when not connected (it will be set low by RS485 chip when RO is enabled)
gpio_clear(USART_PORT(SENSOR_SDM120_USART), USART_PIN_RX(SENSOR_SDM120_USART)); // pull down to avoid noise when not connected (it will be set low by RS485 chip when RO is enabled)
// setup USART parameters for electricity meter
usart_set_baudrate(USART(SENSOR_SDM120_USART), 2400); // get baud rate by scrolling through the measurements on the electricity meter's screen (default 2400)
@ -123,68 +122,73 @@ void sensor_sdm120_setup(void)
gpio_clear(GPIO(SENSOR_SDM120_REDE_PORT),GPIO(SENSOR_SDM120_REDE_PIN)); // disable driver output and enable receive output
// reset states
tx_i = 0;
tx_size = 0;
rx_i = 0;
tx_used = 0;
rx_used = 0;
sensor_sdm120_measurement_received = false;
}
void sensor_sdm120_measurement_request(uint8_t address, enum sensor_sdm120_measurement_type_t type)
{
if (tx_i!=0) { // transmission is ongoing
if (tx_used!=0) { // transmission is ongoing
return;
}
if (type>=SENSOR_SDM120_MAX) { // invalid type
return;
}
tx_buffer[0] = address; // set slave device address
tx_buffer[1] = 0x04; // set function to read 3X registers
tx_buffer[2] = register_input[type]>>8; // set high register address
tx_buffer[3] = register_input[type]; // set low register address
tx_buffer[4] = 0; // set high number of registers to read
tx_buffer[5] = 2; // set low number of register to read (the measurement are encoded using 32 bits IEE745 float, and register hold 16 bits, thus we want to read 2 registers
uint16_t crc = crc_modbus(tx_buffer, 6); // compute error check
tx_buffer[6] = crc; // set low error check
tx_buffer[7] = crc>>8; // set high error check
tx_size = 8; // set request size
uint8_t packet[6]; // buffer to build ModBus message (without error check)
packet[0] = address; // set slave device address
packet[1] = 0x04; // set function to read 3X registers
packet[2] = register_input[type]>>8; // set high register address
packet[3] = register_input[type]; // set low register address
packet[4] = 0; // set high number of registers to read
packet[5] = 2; // set low number of register to read (the measurement are encoded using 32 bits IEE745 float, and register hold 16 bits, thus we want to read 2 registers
uint16_t crc = crc_modbus(packet, LENGTH(packet)); // compute error check
for (uint8_t i=0; i<LENGTH(packet); i++) {
tx_buffer[LENGTH(packet)-i+1] = packet[i]; // copy packet to tx buffer in reverse order (this is how sending is implemented)
}
tx_buffer[1] = crc; // set low error check
tx_buffer[0] = crc>>8; // set high error check
tx_used = LENGTH(packet)+2; // set request size
rx_used = 0; // reset reset buffer
sensor_sdm120_measurement_received = false; // reset measurement flag
gpio_set(GPIO(SENSOR_SDM120_REDE_PORT),GPIO(SENSOR_SDM120_REDE_PIN)); // enable driver output and disable receive output
USART_SR(USART(SENSOR_SDM120_USART)) &= USART_SR_TXE; // clear interrupt flag
usart_enable_tx_interrupt(USART(SENSOR_SDM120_USART)); // enable interrupt to send other bytes
usart_send(USART(SENSOR_SDM120_USART),tx_buffer[tx_i++]); // start transmission
usart_send(USART(SENSOR_SDM120_USART),tx_buffer[--tx_used]); // start transmission
}
float sensor_sdm120_measurement_decode(void)
{
float measurement = 0; //NAN; // decoded measurement to return (invalid in the beginning)
float measurement = NAN; // decoded measurement to return (invalid in the beginning)
if (!sensor_sdm120_measurement_received) { // no measurement received
return NAN;
} else {
sensor_sdm120_measurement_received = false; // reset flag
}
if (rx_i<5) { // not a complete response (minimum is address, function, size/error, error check low, error check high)
if (rx_used<5) { // not a complete response (minimum is address, function, size/error, error check low, error check high)
return NAN;
}
if (crc_modbus(rx_buffer,rx_i)) { // checksum error
return NAN;
}
if (rx_buffer[1]&0x80) { // error condition received
return measurement; // TODO decode the error condition
} else if (rx_buffer[1]==0x04) { // read 3xxxx input register response received
if (rx_i<5 || rx_i-5!=tx_buffer[2]) { // wrong response size
return NAN;
if (crc_modbus(rx_buffer,rx_used)==0 && (rx_buffer[1]&0x80)==0) { // no checksum error, no error condition
switch (rx_buffer[1]) {
case 0x04: // read 3xxxx input register response received
if (rx_buffer[2]==0x04 && rx_used>=(4+5)) { // 2 registers received, corresponds to implemented request
// convert big endian received float value to little endian return value
uint8_t* convert = (uint8_t*)&measurement;
convert[0] = rx_buffer[6];
convert[1] = rx_buffer[5];
convert[2] = rx_buffer[4];
convert[3] = rx_buffer[3];
}
break;
case 0x03: // read 4xxx holding register response received
break; // not supported currently
case 0x10: // write 4xxx holding register response received
break; // not supported currently
default: // unknown function response received
break; // nothing to do
}
if (tx_buffer[2]!=4) { // the code only supports reading a measurement on two registers
return NAN;
}
measurement = (float)((tx_buffer[3]<<24)+(tx_buffer[4]<<16)+(tx_buffer[5]<<8)+(tx_buffer[6]<<0)); // decode big endian encoded float measurement value
measurement = 0;
} else if (rx_buffer[1]==0x04) { // read 4xxx holding register response received
// not supported currently
} else if (rx_buffer[1]==0x10) { // write 4xxx holding register response received
// not supported currently
} else { // unknown function response received
return NAN;
}
rx_used = 0; // reset rx_buffer usage
return measurement;
}
@ -192,35 +196,36 @@ float sensor_sdm120_measurement_decode(void)
void USART_ISR(SENSOR_SDM120_USART)(void)
{
if (usart_get_interrupt_source(USART(SENSOR_SDM120_USART), USART_SR_TXE)) { // data has been transmitted
if (tx_i<tx_size && tx_i<LENGTH(tx_buffer)) { // not all bytes transmitted
usart_send(USART(SENSOR_SDM120_USART),tx_buffer[tx_i++]); // transmit next byte (clears flag)
} else { // request transmitted
if (tx_used) { // not all bytes transmitted
usart_send(USART(SENSOR_SDM120_USART),tx_buffer[--tx_used]); // transmit next byte (clears flag)
} else { // all bytes transmitted
usart_disable_tx_interrupt(USART(SENSOR_SDM120_USART)); // disable transmit interrupt
USART_SR(USART(SENSOR_SDM120_USART)) &= ~USART_SR_TXE; // clear flag
USART_CR1(USART(SENSOR_SDM120_USART)) |= USART_CR1_TCIE; // enable transfer complete interrupt
tx_i = 0; // ready for next transmission
}
}
if (usart_get_interrupt_source(USART(SENSOR_SDM120_USART), USART_SR_TC)) { // data has been transmitted
if (usart_get_interrupt_source(USART(SENSOR_SDM120_USART), USART_SR_TC)) { // data has been completely transmitted
USART_CR1(USART(SENSOR_SDM120_USART)) |= USART_CR1_TCIE; // disable transfer complete interrupt
USART_SR(USART(SENSOR_SDM120_USART)) &= ~USART_SR_TC; // clear flag
gpio_clear(GPIO(SENSOR_SDM120_REDE_PORT),GPIO(SENSOR_SDM120_REDE_PIN)); // disable driver output and enable receive output
tx_i = 0; // ready for next transmission
}
if (usart_get_interrupt_source(USART(SENSOR_SDM120_USART), USART_SR_RXNE)) { // data has been received
led_toggle();
if (rx_i<LENGTH(rx_buffer)) { // receiving response
rx_buffer[rx_i++] = usart_recv(USART(SENSOR_SDM120_USART)); // put received byte in buffer (clears flag)
if (rx_i>=5 && rx_buffer[2]&0x80) { // error condition response received
if (gpio_get(GPIO(SENSOR_SDM120_REDE_PORT),GPIO(SENSOR_SDM120_REDE_PIN))) { // not in receiver mode
USART_SR(USART(SENSOR_SDM120_USART)) &= ~USART_SR_RXNE; // clear flag, ignore received data
} else if (rx_used<LENGTH(rx_buffer)) { // receiving response
rx_buffer[rx_used++] = usart_recv(USART(SENSOR_SDM120_USART)); // put received byte in buffer (clears flag)
if (rx_used==1 && rx_buffer[0]==0) { // this is wrong decoding because the signal is low on idle (and the 0 broadcast device address is not supported)
rx_used = 0; // reset buffer
} else if (rx_used>=5 && (rx_buffer[1]&0x80)) { // error condition response received
sensor_sdm120_measurement_received = true; // notify used response has been received
} else if (rx_i>=5 && (uint8_t)(rx_i-5)>=rx_buffer[3] && (rx_buffer[2]==0x04 || rx_buffer[2]==0x03)) { // read input or holding register response received
} else if (rx_used>=5 && (uint8_t)(rx_used-5)>=rx_buffer[2] && (rx_buffer[1]==0x04 || rx_buffer[1]==0x03)) { // read input or holding register response received
sensor_sdm120_measurement_received = true; // notify used response has been receive
} else if (rx_i>=8 && rx_buffer[2]==0x10) { // write holding register response received
} else if (rx_used>=8 && rx_buffer[1]==0x10) { // write holding register response received
sensor_sdm120_measurement_received = true; // notify used response has been receive
}
} else { // buffer full and unknown response received
rx_i = 0; // clear buffer (not clearing the flag will restart this ISR)
//USART_SR(USART(SENSOR_SDM120_USART)) &= ~USART_SR_RXNE; // clear flag
USART_SR(USART(SENSOR_SDM120_USART)) &= ~USART_SR_RXNE; // clear flag (reading measurement will clear buffer)
//rx_used = 0; // clear buffer (not clearing the flag will restart this ISR)
}
}
}

4
main.c
View File

@ -237,10 +237,10 @@ void main(void)
}
while (sensor_sdm120_measurement_received) { // measurement from electricity meter received
float measurement = sensor_sdm120_measurement_decode(); // decode measurement
if (measurement==NAN) {
if (isnan(measurement)) {
printf("error in measurement response\n");
} else {
printf("measurement: %f\n",measurement);
printf("measurement: %.01f\n",measurement);
}
}
while (button_flag) { // user pressed button