From 817742862a867673e4cbdb85d274481f7482e1ae Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Wed, 3 Jul 2013 19:13:56 +0300 Subject: [PATCH] Implement current and voltage monitoring --- arducontrol/Makefile | 2 +- arducontrol/arducontrol.c | 105 ++++++++++++++++++++++++++++++++++++++ arducontrol/commands.h | 8 ++- 3 files changed, 113 insertions(+), 2 deletions(-) diff --git a/arducontrol/Makefile b/arducontrol/Makefile index 1ffdd1d..22864ff 100644 --- a/arducontrol/Makefile +++ b/arducontrol/Makefile @@ -1,3 +1,3 @@ include ../common/build.mk -arducontrol.elf: motorola.o packet.o serial.o timer.o +arducontrol.elf: adc.o motorola.o packet.o serial.o timer.o diff --git a/arducontrol/arducontrol.c b/arducontrol/arducontrol.c index 7b0c636..d09fc09 100644 --- a/arducontrol/arducontrol.c +++ b/arducontrol/arducontrol.c @@ -11,6 +11,10 @@ Connections for Pololu high-powered motor driver: D2 <-> DIR D3 <-> PWM +ADC connections: +ADC0 - current sensor (adjusted for 185 mV/A, centered at Vcc/2) +ADC1 - input voltage (adjusted for divisor of 11) + This is not a complete control device. Rather, it is a low-level bus driver, intended to be controlled with a computer program. In particular, no state is kept about locomotives or solenoids. It is up to the controlling program to @@ -30,6 +34,7 @@ blocks until the operation completes. The command returns as soon as sending its data to the track can start. */ #include +#include "adc.h" #include "commands.h" #include "motorola.h" #include "packet.h" @@ -50,6 +55,18 @@ volatile uint8_t recv_overrun = 0; uint8_t cmd_buf[15]; uint8_t cmd_length; +uint16_t track_current_samples[16] = { 0 }; +uint8_t track_current_head = 0; +volatile uint16_t track_current_sum = 0; +uint16_t overcurrent_limit = 1000<<4; +uint8_t overcurrent_sent = 0; + +uint16_t input_voltage_samples[16] = { 0 }; +uint8_t input_voltage_head = 0; +volatile uint16_t input_voltage_sum = 0; + +volatile uint8_t adc_state = 0; + void process_commands(); uint8_t process_command(); @@ -60,6 +77,7 @@ int main() serial_init(9600); timer_start_hz(0, 80000, 1); + adc_init(); sei(); @@ -73,6 +91,23 @@ int main() } if(recv_fill>0) process_commands(); + if(!(adc_state&1)) + { + ++adc_state; + adc_read_async(adc_state>>1); + } + if(track_current_sum>overcurrent_limit) + { + PORTD &= ~0x08; + if(!overcurrent_sent) + { + overcurrent_sent = 1; + serial_write(0xFE); + serial_write(OVERCURRENT); + } + } + else + overcurrent_sent = 0; } return 0; @@ -152,6 +187,38 @@ uint8_t process_command() else PORTD &= ~0x08; } + else if(cmd_buf[0]==READ_TRACK_CURRENT) + { + if(cmd_length!=1) + return LENGTH_ERROR; + + serial_write(0xFC); + serial_write(TRACK_CURRENT); + uint16_t value = track_current_sum>>4; + serial_write(value>>8); + serial_write(value); + } + else if(cmd_buf[0]==SET_OVERCURRENT_LIMIT) + { + if(cmd_length!=3) + return LENGTH_ERROR; + + if(cmd_buf[1]&0xF0) + return INVALID_VALUE; + + overcurrent_limit = (cmd_buf[1]<<12) | (cmd_buf[2]<<4); + } + else if(cmd_buf[0]==READ_INPUT_VOLTAGE) + { + if(cmd_length!=1) + return LENGTH_ERROR; + + serial_write(0xFC); + serial_write(INPUT_VOLTAGE); + uint16_t value = (input_voltage_sum>>3)*5; + serial_write(value>>8); + serial_write(value); + } else if(cmd_buf[0]==MOTOROLA_SPEED || cmd_buf[0]==MOTOROLA_SPEED_DIRECTION || cmd_buf[0]==MOTOROLA_SPEED_FUNCTION) { if(cmd_length!=4) @@ -287,3 +354,41 @@ static inline void tick() } TIMER_SET_CALLBACK(0, tick) + +static inline void adc_complete(uint16_t value) +{ + if(adc_state==1) + { + // Convert to milliamps: (v*5/1024-2.5)*1000/0.185 + if(value<512) // Ignore negative current readings + value = 0; + else if(value>663) // Limit range so averaging won't overflow + value = 4000; + else + value = (value-512)*132/5; + + uint8_t i = track_current_head; + track_current_sum -= track_current_samples[i]; + track_current_samples[i] = value; + track_current_sum += value; + track_current_head = (i+1)&15; + } + else if(adc_state==3) + { + // Convert to centivolts: (v*5/1024)*100*11 + if(value>744) // Limit range so averaging won't overflow + value = 4000; + else + value = value*43/8; + + uint8_t i = input_voltage_head; + input_voltage_sum -= input_voltage_samples[i]; + input_voltage_samples[i] = value; + input_voltage_sum += value; + input_voltage_head = (i+1)&15; + } + + ++adc_state; +} + +ADC_SET_CALLBACK(adc_complete) diff --git a/arducontrol/commands.h b/arducontrol/commands.h index bbd8dc8..64cbe54 100644 --- a/arducontrol/commands.h +++ b/arducontrol/commands.h @@ -5,6 +5,9 @@ enum Command { POWER_ON = 0x01, POWER_OFF = 0x02, + READ_TRACK_CURRENT = 0x03, + SET_OVERCURRENT_LIMIT = 0x04, + READ_INPUT_VOLTAGE = 0x05, MOTOROLA_SPEED = 0x11, MOTOROLA_REVERSE = 0x12, MOTOROLA_SPEED_DIRECTION = 0x13, @@ -15,7 +18,10 @@ enum Command FRAMING_ERROR = 0x82, INVALID_COMMAND = 0x83, LENGTH_ERROR = 0x84, - INVALID_VALUE = 0x85 + INVALID_VALUE = 0x85, + OVERCURRENT = 0xA0, + TRACK_CURRENT = 0xC0, + INPUT_VOLTAGE = 0xC1 }; #endif -- 2.43.0