initial commit
This commit is contained in:
40
eeprom.h
Normal file
40
eeprom.h
Normal file
@ -0,0 +1,40 @@
|
||||
void EEPROM_write_char(uint16_t address, unsigned char data)
|
||||
{
|
||||
/* Wait for completion of previous write */
|
||||
while(EECR & (1<<EEPE));
|
||||
/* Set up address and Data Registers */
|
||||
EEAR = address;
|
||||
EEDR = data;
|
||||
/* Write logical one to EEMPE */
|
||||
EECR |= (1<<EEMPE);
|
||||
/* Start eeprom write by setting EEPE */
|
||||
EECR |= (1<<EEPE);
|
||||
}
|
||||
|
||||
unsigned char EEPROM_read_char(uint16_t uiAddress)
|
||||
{
|
||||
/* Wait for completion of previous write */
|
||||
while(EECR & (1<<EEPE));
|
||||
/* Set up address register */
|
||||
EEAR = uiAddress;
|
||||
/* Start eeprom read by writing EERE */
|
||||
EECR |= (1<<EERE);
|
||||
/* Return data from Data Register */
|
||||
return EEDR;
|
||||
}
|
||||
|
||||
void EEPROM_write_string(uint16_t address, char* buffer, uint16_t length)
|
||||
{
|
||||
for(uint16_t i = 0; i < length; i++)
|
||||
{
|
||||
EEPROM_write_char( address+i, buffer[i] );
|
||||
}
|
||||
}
|
||||
|
||||
void EEPROM_read_string(uint16_t address, char* buffer, uint16_t length)
|
||||
{
|
||||
for(uint16_t i = 0; i < length; i++)
|
||||
{
|
||||
buffer[i] = EEPROM_read_char( address+i);
|
||||
}
|
||||
}
|
301
main.cpp
Normal file
301
main.cpp
Normal file
@ -0,0 +1,301 @@
|
||||
#include <avr/io.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include "serial.h"
|
||||
#include "writepin.h"
|
||||
#include "train.h"
|
||||
#include "eeprom.h"
|
||||
|
||||
const char *bit_rep[16] =
|
||||
{
|
||||
[ 0] = "0000", [ 1] = "0001", [ 2] = "0010", [ 3] = "0011",
|
||||
[ 4] = "0100", [ 5] = "0101", [ 6] = "0110", [ 7] = "0111",
|
||||
[ 8] = "1000", [ 9] = "1001", [10] = "1010", [11] = "1011",
|
||||
[12] = "1100", [13] = "1101", [14] = "1110", [15] = "1111",
|
||||
};
|
||||
|
||||
#define MAX_TRAINS 16
|
||||
#define COMMAND_BUFFER_SIZE 64
|
||||
#define SNPRINTF_BUFFER_SIZE 64
|
||||
|
||||
char buffer[SNPRINTF_BUFFER_SIZE];
|
||||
|
||||
uint16_t storedTrains = 0;
|
||||
Train trains[MAX_TRAINS];
|
||||
|
||||
#define TICK_MAX 255
|
||||
uint8_t tick = 0;
|
||||
|
||||
bool autoff = true;
|
||||
bool powerIsOn = true;
|
||||
|
||||
ISR(TIMER0_OVF_vect)
|
||||
{
|
||||
if(powerIsOn)
|
||||
{
|
||||
++tick;
|
||||
if(tick == TICK_MAX)
|
||||
{
|
||||
for(uint16_t i = 0; i < storedTrains; i++) trains[i].resendSpeed();
|
||||
if(autoff)
|
||||
{
|
||||
bool trainsRunning = false;
|
||||
for(uint16_t i = 0; i < storedTrains; i++) trainsRunning = trainsRunning || trains[i].getSpeed();
|
||||
if(!trainsRunning)
|
||||
{
|
||||
powerIsOn = false;
|
||||
Train::setOutput(Train::OFF);
|
||||
}
|
||||
}
|
||||
tick = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
Train::setOutput(Train::HIGH);
|
||||
_delay_us(200);
|
||||
Train::setOutput(Train::LOW);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void save_state()
|
||||
{
|
||||
EEPROM_write_char( 0, storedTrains );
|
||||
EEPROM_write_char( 1, autoff );
|
||||
for(uint16_t i = 0; i < storedTrains; i++)
|
||||
{
|
||||
EEPROM_write_char( i+32, trains[i].getAddress());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void restore_state()
|
||||
{
|
||||
storedTrains = EEPROM_read_char(0);
|
||||
autoff = EEPROM_read_char(1);
|
||||
if(storedTrains > MAX_TRAINS )
|
||||
{
|
||||
for(uint16_t i = 0; i < MAX_TRAINS+32; i++) EEPROM_write_char(i, 0);
|
||||
storedTrains = 0;
|
||||
}
|
||||
else for(uint8_t i = 0; i <= storedTrains; i++)
|
||||
{
|
||||
uint8_t address = EEPROM_read_char(32+i);
|
||||
trains[i].setAddress(address);
|
||||
}
|
||||
}
|
||||
|
||||
inline static void printHelp(Serial* serial)
|
||||
{
|
||||
serial->write_p(PSTR("Available Commands: \n\
|
||||
help : Show this prompt.\n\
|
||||
train add [address] : Add train.\n\
|
||||
train delete : Delete last train.\n\
|
||||
train list : Print list of saved trains.\n\
|
||||
train [nn] stop : Stop nth train.\n\
|
||||
train [nn] speed [sp] : Set nth train speed.\n\
|
||||
train [nn] function [x] : Toggle x'ed fuction on train n.\n\
|
||||
train [nn] reverse : Reverse train n.\n\
|
||||
stop : stop all trains\n\
|
||||
power off : power off the rail\n\
|
||||
power on : power on the rail\n\
|
||||
power auto : power off the rail when no trains are moveing\n\
|
||||
dump : prints epprom contence\n\
|
||||
erase : Erase epprom.\n"));
|
||||
}
|
||||
|
||||
|
||||
void trainDispatch(char* inBuffer, Serial* serial)
|
||||
{
|
||||
if(powerIsOn == false)
|
||||
{
|
||||
powerIsOn = true;
|
||||
Train::setOutput(Train::LOW);
|
||||
_delay_ms(100);
|
||||
}
|
||||
if( strcmp(inBuffer, "add") == 0 )
|
||||
{
|
||||
char* token = strtok(NULL, " ");
|
||||
uint8_t address = strtol(token, nullptr, 2 );
|
||||
if(address != 0 && storedTrains < MAX_TRAINS)
|
||||
{
|
||||
trains[storedTrains].setAddress(address);
|
||||
|
||||
uint8_t size = snprintf(buffer, SNPRINTF_BUFFER_SIZE, "TRAIN saved! NUMBER: %u ADRESS: %s%s\n", storedTrains, bit_rep[address >> 4], bit_rep[address & 0x0F]);
|
||||
serial->write(buffer, size);
|
||||
|
||||
storedTrains++;
|
||||
save_state();
|
||||
}
|
||||
else serial->write_p(PSTR("Usage: train add [address]"));
|
||||
}
|
||||
else if( strcmp(inBuffer, "delete") == 0)
|
||||
{
|
||||
serial->write_p(PSTR("Train: "));
|
||||
serial->write(storedTrains);
|
||||
serial->write_p(PSTR(" deleted\n"));
|
||||
storedTrains--;
|
||||
}
|
||||
else if( strcmp(inBuffer, "list") == 0 )
|
||||
{
|
||||
serial->write_p(PSTR("Trains:\n"));
|
||||
for(uint8_t i = 0; i < storedTrains; i++)
|
||||
{
|
||||
snprintf(buffer, SNPRINTF_BUFFER_SIZE, "NUMBER: %u ID: %s%s CURRENT SPD: %u\n", i, bit_rep[trains[i].getAddress() >> 4], bit_rep[trains[i].getAddress() & 0x0F], trains[i].getSpeed());
|
||||
serial->write(buffer, SNPRINTF_BUFFER_SIZE);
|
||||
}
|
||||
serial->putChar('\n');
|
||||
}
|
||||
else\
|
||||
{
|
||||
uint8_t id = strtol(inBuffer, nullptr, 10);
|
||||
if(id < storedTrains )
|
||||
{
|
||||
char* token = strtok(NULL, " ");
|
||||
if( strcmp(token, "speed") == 0 )
|
||||
{
|
||||
token = strtok(NULL, " ");
|
||||
trains[id].setSpeed(atoi(token));
|
||||
}
|
||||
else if( strcmp(token, "function") == 0 )
|
||||
{
|
||||
token = strtok(NULL, " ");
|
||||
trains[id].sendFunction(atoi(token));
|
||||
}
|
||||
else if( strcmp(token, "reverse") == 0 ) trains[id].reverse();
|
||||
else if( strcmp(token, "stop") )trains[id].setSpeed(0);
|
||||
else serial->write_p(PSTR("Not a valid command\n"));
|
||||
}
|
||||
else serial->write_p(PSTR("Id out of range.\n"));
|
||||
}
|
||||
}
|
||||
|
||||
void powerDispatch(char* token, Serial* serial)
|
||||
{
|
||||
if(strcmp(token, "off") == 0)
|
||||
{
|
||||
for(uint16_t i = 0; i < storedTrains; i++)
|
||||
{
|
||||
trains[i].setSpeed(0);
|
||||
}
|
||||
Train::setOutput(Train::OFF);
|
||||
powerIsOn = false;
|
||||
}
|
||||
else if( strcmp(token, "on") == 0)
|
||||
{
|
||||
for(uint16_t i = 0; i < storedTrains; i++)
|
||||
{
|
||||
trains[i].setSpeed(0);
|
||||
}
|
||||
Train::setOutput(Train::LOW);
|
||||
}
|
||||
else if(strcmp(token, "auto") == 0)
|
||||
{
|
||||
token = strtok(NULL, " ");
|
||||
if(strcmp(token, "on") == 0)
|
||||
{
|
||||
autoff = true;
|
||||
serial->write_p(PSTR("auto power off turned on.\n"));
|
||||
save_state();
|
||||
}
|
||||
else if(strcmp(token, "off") == 0)
|
||||
{
|
||||
autoff = false;
|
||||
serial->write_p(PSTR("auto power off turned off.\n"));
|
||||
save_state();
|
||||
}
|
||||
else
|
||||
{
|
||||
serial->write_p(PSTR("argument must be \"on\" or \"off\". This feature is currently "));
|
||||
autoff ? serial->write_p(PSTR("on.\n")) : serial->write_p(PSTR("off.\n"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void serialDispatch(Serial* serial)
|
||||
{
|
||||
if(serial->dataIsWaiting())
|
||||
{
|
||||
char buffer[COMMAND_BUFFER_SIZE];
|
||||
unsigned int length = serial->getString(buffer, COMMAND_BUFFER_SIZE);
|
||||
if(length > 2)
|
||||
{
|
||||
serial->write_p(PSTR("Got: "));
|
||||
serial->putChar('\"');
|
||||
serial->write(buffer, length);
|
||||
serial->write("\"\n");
|
||||
char* token = strtok(buffer, " ");
|
||||
if(length > 4 && strcmp(token, "train") == 0)
|
||||
{
|
||||
token = strtok(NULL, " ");
|
||||
trainDispatch(token, serial);
|
||||
}
|
||||
else if(length > 4 && strncmp(token, "erase", 4) == 0)
|
||||
{
|
||||
for(uint16_t i = 0; i < MAX_TRAINS+1; i++) EEPROM_write_char(i, 0);
|
||||
serial->write_p(PSTR("EEPROM erased\n"));
|
||||
storedTrains = 0;
|
||||
}
|
||||
else if(length > 3 && strcmp(token, "dump") == 0)
|
||||
{
|
||||
for(uint16_t i = 0; i < MAX_TRAINS+32; i++)
|
||||
{
|
||||
if(i != 0) serial->putChar(',');
|
||||
serial->write((uint16_t)EEPROM_read_char(i));
|
||||
}
|
||||
serial->putChar('\n');
|
||||
}
|
||||
else if(length > 3 && strcmp(token, "stop") == 0)
|
||||
{
|
||||
for(uint16_t i = 0; i < storedTrains; i++)
|
||||
{
|
||||
trains[i].setSpeed(0);
|
||||
}
|
||||
}
|
||||
else if(length > 3 && strcmp(token, "power") == 0)
|
||||
{
|
||||
token = strtok(NULL, " ");
|
||||
powerDispatch(token, serial);
|
||||
}
|
||||
else if(length > 3 && strcmp(token, "help") == 0)
|
||||
{
|
||||
printHelp(serial);
|
||||
}
|
||||
else
|
||||
{
|
||||
serial->putChar('\"');
|
||||
serial->write(buffer, length);
|
||||
serial->putChar('\"');
|
||||
serial->write_p(PSTR(" is not a valid command\n"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
TCNT0 = 0;
|
||||
TIMSK0 = 0b00000001; //turn on timer0 interupt on OCIEB
|
||||
TCCR0B = (1<<CS02) /*| (1<<CS00)*/; // run timer0 with /1024 scaler
|
||||
|
||||
DDRD = (1 << PD2) | (1 << PD3);
|
||||
|
||||
restore_state();
|
||||
|
||||
autoff ? Train::setOutput(Train::OFF) : Train::setOutput(Train::LOW);
|
||||
|
||||
sei();
|
||||
|
||||
Serial serial;
|
||||
|
||||
serial.write_p(PSTR("TrainController v0.1 starting\n"));
|
||||
while(true)
|
||||
{
|
||||
serialDispatch(&serial);
|
||||
}
|
||||
return 0;
|
||||
}
|
112
ringbuffer.h
Executable file
112
ringbuffer.h
Executable file
@ -0,0 +1,112 @@
|
||||
/*UVOS*/
|
||||
|
||||
/* This file is part of TelemetrySystem.
|
||||
*
|
||||
* TelemetrySystem is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License (LGPL) version 3 as published by
|
||||
* the Free Software Foundation.
|
||||
*
|
||||
* TelemetrySystem is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with TelemetrySystem. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
template < int BUFFER_SIZE >
|
||||
class RingBuffer
|
||||
{
|
||||
private:
|
||||
|
||||
uint_fast16_t _headIndex = 0;
|
||||
uint_fast16_t _tailIndex = 0;
|
||||
uint8_t _buffer[BUFFER_SIZE];
|
||||
|
||||
public:
|
||||
|
||||
RingBuffer()
|
||||
{
|
||||
flush();
|
||||
}
|
||||
|
||||
uint_fast16_t remaining()
|
||||
{
|
||||
return (_headIndex-_tailIndex);
|
||||
}
|
||||
|
||||
bool isOverun(uint_fast16_t margin = 0)
|
||||
{
|
||||
return remaining() >= BUFFER_SIZE - margin;
|
||||
}
|
||||
|
||||
bool isEmpty()
|
||||
{
|
||||
return _tailIndex >= _headIndex;
|
||||
}
|
||||
|
||||
uint8_t read()
|
||||
{
|
||||
if(!isEmpty())
|
||||
{
|
||||
_tailIndex++;
|
||||
return _buffer[(_tailIndex - 1) % BUFFER_SIZE];
|
||||
}
|
||||
else return '\0';
|
||||
}
|
||||
|
||||
unsigned int read( uint8_t* buffer, unsigned int length )
|
||||
{
|
||||
unsigned int i = 0;
|
||||
for(; i < length && !isEmpty(); i++)
|
||||
{
|
||||
buffer[i] = read();
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
void write( uint8_t in )
|
||||
{
|
||||
if (_headIndex - BUFFER_SIZE > 0 && _tailIndex - BUFFER_SIZE > 0)
|
||||
{
|
||||
_headIndex -= BUFFER_SIZE;
|
||||
_tailIndex -= BUFFER_SIZE;
|
||||
}
|
||||
_buffer[_headIndex % BUFFER_SIZE] = in;
|
||||
_headIndex++;
|
||||
}
|
||||
|
||||
void write( uint8_t* buffer, unsigned int length )
|
||||
{
|
||||
for(uint8_t i = 0; i < length; i++) write(buffer[i]);
|
||||
}
|
||||
|
||||
void flush()
|
||||
{
|
||||
_headIndex = 0;
|
||||
_tailIndex = 0;
|
||||
for(int i = 0; i < BUFFER_SIZE; i++) _buffer[i] = ' ';
|
||||
}
|
||||
|
||||
unsigned int getString(uint8_t terminator, char* buffer, const unsigned int bufferLength)
|
||||
{
|
||||
unsigned int i = 0;
|
||||
for(; i <= remaining() && i <= BUFFER_SIZE && _buffer[(_tailIndex+i) % BUFFER_SIZE] != terminator; i++);
|
||||
|
||||
if( i < remaining() && i > 0)
|
||||
{
|
||||
if(i > bufferLength-1) i = bufferLength-1;
|
||||
read((uint8_t*)buffer, i);
|
||||
buffer[i]='\0';
|
||||
_tailIndex++;
|
||||
}
|
||||
else if(i == 0) _tailIndex++;
|
||||
else i = 0;
|
||||
|
||||
return i;
|
||||
}
|
||||
};
|
127
serial.cpp
Normal file
127
serial.cpp
Normal file
@ -0,0 +1,127 @@
|
||||
#include "serial.h"
|
||||
#include "ringbuffer.h"
|
||||
|
||||
RingBuffer<SERIAL_BUFFER_SIZE> rxBuffer;
|
||||
|
||||
bool stopped = false;
|
||||
|
||||
ISR (USART_RX_vect) //I have seen worse interrupt sintax
|
||||
{
|
||||
rxBuffer.write(UDR0);
|
||||
if(serialFlowControl && !stopped && rxBuffer.isOverun(32))
|
||||
{
|
||||
loop_until_bit_is_set(UCSR0A, UDRE0);
|
||||
UDR0 = 0x13;
|
||||
stopped = true;
|
||||
}
|
||||
}
|
||||
|
||||
Serial::Serial()
|
||||
{
|
||||
UBRR0H = UBRRH_VALUE;
|
||||
UBRR0L = UBRRL_VALUE;
|
||||
UCSR0C = _BV(UCSZ01) | _BV(UCSZ00);
|
||||
UCSR0B = _BV(RXEN0) | _BV(TXEN0); //Enable RX and TX
|
||||
UCSR0B |= (1 << RXCIE0); //Enable Rx interuppt
|
||||
}
|
||||
|
||||
void Serial::putChar(const char c)
|
||||
{
|
||||
loop_until_bit_is_set(UCSR0A, UDRE0);
|
||||
UDR0 = c;
|
||||
}
|
||||
|
||||
void Serial::write(const char* in, const unsigned int length)
|
||||
{
|
||||
for(unsigned int i = 0; i < length && in[i] != '\0'; i++)
|
||||
{
|
||||
putChar(in[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void Serial::write_p(const char in[])
|
||||
{
|
||||
cli();
|
||||
char ch = pgm_read_byte(in);
|
||||
while (ch != '\0')
|
||||
{
|
||||
putChar(ch);
|
||||
in++;
|
||||
ch = pgm_read_byte(in);
|
||||
}
|
||||
sei();
|
||||
}
|
||||
|
||||
void Serial::write(const char in[])
|
||||
{
|
||||
for(unsigned int i = 0; i < strlen(in); i++)
|
||||
{
|
||||
putChar(in[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Serial::write(int32_t in)
|
||||
{
|
||||
if(in == 0)
|
||||
{
|
||||
putChar('0');
|
||||
}
|
||||
else
|
||||
{
|
||||
bool flag = false;
|
||||
char str[64] = { 0 };
|
||||
int16_t i = 62;
|
||||
if (in < 0)
|
||||
{
|
||||
flag = true;
|
||||
in = abs(in);
|
||||
}
|
||||
|
||||
while (in != 0 && i > 0)
|
||||
{
|
||||
str[i--] = (in % 10) + '0';
|
||||
in /= 10;
|
||||
}
|
||||
|
||||
if (flag) str[i--] = '-';
|
||||
write(str + i + 1, 64-(i+1));
|
||||
}
|
||||
}
|
||||
|
||||
bool Serial::dataIsWaiting()
|
||||
{
|
||||
return !rxBuffer.isEmpty();
|
||||
}
|
||||
|
||||
char Serial::getChar()
|
||||
{
|
||||
if(!rxBuffer.isEmpty())
|
||||
{
|
||||
if(serialFlowControl && stopped && !rxBuffer.isOverun(32))
|
||||
{
|
||||
loop_until_bit_is_set(UCSR0A, UDRE0);
|
||||
UDR0 = 0x11;
|
||||
stopped = false;
|
||||
}
|
||||
return rxBuffer.read();
|
||||
}
|
||||
else return '\0';
|
||||
}
|
||||
|
||||
unsigned int Serial::getString(char* buffer, const int bufferLength)
|
||||
{
|
||||
return rxBuffer.getString(_terminator, buffer, bufferLength);
|
||||
}
|
||||
|
||||
unsigned int Serial::read(char* buffer, const unsigned int length )
|
||||
{
|
||||
return rxBuffer.read((uint8_t*)buffer, length);
|
||||
}
|
||||
|
||||
void Serial::flush()
|
||||
{
|
||||
rxBuffer.flush();
|
||||
}
|
||||
|
||||
void Serial::setTerminator(char terminator){_terminator = terminator;}
|
37
serial.h
Normal file
37
serial.h
Normal file
@ -0,0 +1,37 @@
|
||||
#ifndef SERIAL_H
|
||||
#define SERIAL_H
|
||||
|
||||
#define BAUD 38400
|
||||
#define SERIAL_BUFFER_SIZE 128
|
||||
|
||||
#include <util/setbaud.h>
|
||||
#include <avr/io.h>
|
||||
#include <avr/interrupt.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <avr/pgmspace.h>
|
||||
|
||||
const bool serialFlowControl = false;
|
||||
|
||||
class Serial
|
||||
{
|
||||
private:
|
||||
char _terminator = '\n';
|
||||
|
||||
public:
|
||||
Serial();
|
||||
void putChar(const char c);
|
||||
void write(const char* in, const unsigned int length);
|
||||
void write(const char in[]);
|
||||
void write_p(const char in[]); //for flash space strigns
|
||||
void write(const int32_t in);
|
||||
unsigned int read( char* buffer, const unsigned int length );
|
||||
bool dataIsWaiting();
|
||||
char getChar();
|
||||
unsigned int getString(char* buffer, const int bufferLength);
|
||||
void flush();
|
||||
void setTerminator(const char terminator);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
116
train.cpp
Normal file
116
train.cpp
Normal file
@ -0,0 +1,116 @@
|
||||
#include "train.h"
|
||||
|
||||
static volatile unsigned char *_port = &PORTD;
|
||||
|
||||
Train::Train(const uint8_t address): _address(address)
|
||||
{
|
||||
}
|
||||
|
||||
Train::Train()
|
||||
{
|
||||
writePin(_port, _pinHigh, false);
|
||||
writePin(_port, _pinLow, true);
|
||||
_address = 0;
|
||||
}
|
||||
|
||||
void Train::setAddress(const uint8_t address)
|
||||
{
|
||||
_address = address;
|
||||
}
|
||||
|
||||
uint8_t Train::getAddress()
|
||||
{
|
||||
return _address;
|
||||
}
|
||||
|
||||
void Train::setOutput(const uint8_t state)
|
||||
{
|
||||
if(state == HIGH)
|
||||
{
|
||||
writePin(_port, _pinLow, true);
|
||||
_delay_us(5);
|
||||
writePin(_port, _pinHigh, true);
|
||||
}
|
||||
else if (state == LOW)
|
||||
{
|
||||
writePin(_port, _pinHigh, false);
|
||||
_delay_us(5);
|
||||
writePin(_port, _pinLow, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
writePin(_port, _pinHigh, false);
|
||||
writePin(_port, _pinLow, true);
|
||||
}
|
||||
}
|
||||
|
||||
void Train::sendBit(const bool bit)
|
||||
{
|
||||
if(bit)
|
||||
{
|
||||
setOutput(HIGH);
|
||||
_delay_us(170);
|
||||
setOutput(LOW);
|
||||
_delay_us(25);
|
||||
}
|
||||
else
|
||||
{
|
||||
setOutput(HIGH);
|
||||
_delay_us(20);
|
||||
setOutput(LOW);
|
||||
_delay_us(175);
|
||||
}
|
||||
}
|
||||
|
||||
void Train::sendAddress()
|
||||
{
|
||||
for(uint8_t i = 0; i < 8; i++)
|
||||
{
|
||||
sendBit(_address & (1 << i));
|
||||
}
|
||||
}
|
||||
|
||||
void Train::sendData(const uint8_t data)
|
||||
{
|
||||
for(uint8_t j = 0; j < SEND_COUNT; j++)
|
||||
{
|
||||
sendAddress();
|
||||
for(uint8_t i = 0; i < 5; i++)
|
||||
{
|
||||
sendBit(data & (1 << i));
|
||||
sendBit(data & (1 << i));
|
||||
}
|
||||
_delay_ms(2);
|
||||
}
|
||||
}
|
||||
|
||||
void Train::setSpeed(uint8_t speed)
|
||||
{
|
||||
if(speed > 0) ++speed;
|
||||
if(speed <= 15)
|
||||
{
|
||||
lastSpeed = speed;
|
||||
sendData(speed << 1);
|
||||
}
|
||||
}
|
||||
|
||||
void Train::resendSpeed()
|
||||
{
|
||||
uint8_t data = lastSpeed;
|
||||
sendData(data << 1);
|
||||
}
|
||||
|
||||
uint8_t Train::getSpeed()
|
||||
{
|
||||
return lastSpeed;
|
||||
}
|
||||
|
||||
void Train::reverse()
|
||||
{
|
||||
sendData(1 << 1);
|
||||
}
|
||||
|
||||
void Train::sendFunction(const uint8_t function)
|
||||
{
|
||||
sendData((function << 1) | 1);
|
||||
}
|
49
train.h
Normal file
49
train.h
Normal file
@ -0,0 +1,49 @@
|
||||
#pragma once
|
||||
|
||||
#include "writepin.h"
|
||||
#include <util/delay.h>
|
||||
#include <stdint.h>
|
||||
#include <avr/io.h>
|
||||
|
||||
class Train
|
||||
{
|
||||
private:
|
||||
uint8_t _address;
|
||||
|
||||
static const unsigned char _pinHigh = PD3;
|
||||
static const unsigned char _pinLow = PD2;
|
||||
|
||||
static const uint8_t SEND_COUNT = 4;
|
||||
|
||||
uint8_t lastSpeed = 0;
|
||||
|
||||
void sendBit(const bool bit);
|
||||
void sendAddress();
|
||||
void sendData(const uint8_t data);
|
||||
|
||||
public:
|
||||
|
||||
static const uint8_t HIGH = 2;
|
||||
static const uint8_t LOW = 1;
|
||||
static const uint8_t OFF = 0;
|
||||
|
||||
static void setOutput(const uint8_t state);
|
||||
|
||||
Train(const uint8_t address);
|
||||
Train();
|
||||
|
||||
void resendSpeed();
|
||||
|
||||
void setSpeed(uint8_t speed);
|
||||
|
||||
void reverse();
|
||||
|
||||
uint8_t getAddress();
|
||||
|
||||
uint8_t getSpeed();
|
||||
|
||||
void setAddress(const uint8_t address);
|
||||
|
||||
void sendFunction(const uint8_t function);
|
||||
|
||||
};
|
13
writepin.h
Normal file
13
writepin.h
Normal file
@ -0,0 +1,13 @@
|
||||
#ifndef WRITEPIN_H
|
||||
#define WRITEPIN_H
|
||||
#include <avr/io.h>
|
||||
|
||||
inline void writePin(volatile unsigned char *port, const unsigned char pin, const bool state) //waste 2 cycles
|
||||
{
|
||||
*port &= ~(1 << pin);
|
||||
if(state) *port |= (1 << pin);
|
||||
}
|
||||
|
||||
inline bool readPin( volatile unsigned char *inPort, const unsigned char pin){ return (bool) (*inPort & (1 << pin));}
|
||||
|
||||
#endif
|
Reference in New Issue
Block a user