X-Git-Url: http://git.tdb.fi/?p=model-railway-devices.git;a=blobdiff_plain;f=arducontrol%2Farducontrol.c;h=d09fc09c3766e3dca9d41dbbd0125e250dae8c28;hp=7b0c636b9ffb926ae811a9605a3b17e29806c633;hb=817742862a867673e4cbdb85d274481f7482e1ae;hpb=3c070b8fc92fe0506e29d0c0491038be241f7107 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)