fix reveiced and decode data
This commit is contained in:
parent
9b047ccf41
commit
f0eb5e0f7c
|
@ -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
4
main.c
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue