inital version
This commit is contained in:
164
CL56.cpp
Normal file
164
CL56.cpp
Normal file
@ -0,0 +1,164 @@
|
|||||||
|
#include "CL56.h"
|
||||||
|
|
||||||
|
DualCl56::DualCl56(ShiftReg<16>* shiftReg):
|
||||||
|
_shiftReg(shiftReg)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void DualCl56::tick()
|
||||||
|
{
|
||||||
|
++_currentLit;
|
||||||
|
if(_currentLit > 7)_currentLit = 0;
|
||||||
|
unsigned char bits[2] = {0b10000000>>_currentLit, ~(_segments[_currentLit])};
|
||||||
|
_shiftReg->write(reinterpret_cast<unsigned char*>(&bits));
|
||||||
|
}
|
||||||
|
|
||||||
|
void DualCl56::setString(const char string[], const uint8_t dp)
|
||||||
|
{
|
||||||
|
uint_fast8_t i = 0;
|
||||||
|
for(; i < 8 && string[i] != '\0'; i++)
|
||||||
|
{
|
||||||
|
switch (string[i])
|
||||||
|
{
|
||||||
|
case '\0':
|
||||||
|
case '\n':
|
||||||
|
case ' ':
|
||||||
|
_segments[i] = 0;
|
||||||
|
break;
|
||||||
|
case '0':
|
||||||
|
_segments[i] = ZERO;
|
||||||
|
break;
|
||||||
|
case '1':
|
||||||
|
_segments[i] = ONE;
|
||||||
|
break;
|
||||||
|
case '2':
|
||||||
|
_segments[i] = TOW;
|
||||||
|
break;
|
||||||
|
case '3':
|
||||||
|
_segments[i] = THREE;
|
||||||
|
break;
|
||||||
|
case '4':
|
||||||
|
_segments[i] = FOUR;
|
||||||
|
break;
|
||||||
|
case '5':
|
||||||
|
_segments[i] = FIVE;
|
||||||
|
break;
|
||||||
|
case '6':
|
||||||
|
_segments[i] = SIX;
|
||||||
|
break;
|
||||||
|
case '7':
|
||||||
|
_segments[i] = SEVEN;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '8':
|
||||||
|
_segments[i] = EIGT;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '9':
|
||||||
|
_segments[i] = NINE;
|
||||||
|
break;
|
||||||
|
case 'a':
|
||||||
|
case 'A':
|
||||||
|
_segments[i] = SIGA;
|
||||||
|
break;
|
||||||
|
case 'b':
|
||||||
|
case 'B':
|
||||||
|
_segments[i] = SIGB;
|
||||||
|
break;
|
||||||
|
case 'c':
|
||||||
|
_segments[i] = SIGc;
|
||||||
|
break;
|
||||||
|
case 'C':
|
||||||
|
_segments[i] = SIGC;
|
||||||
|
break;
|
||||||
|
case 'd':
|
||||||
|
case 'D':
|
||||||
|
_segments[i] = SIGD;
|
||||||
|
break;
|
||||||
|
case 'e':
|
||||||
|
case 'E':
|
||||||
|
_segments[i] = SIGE;
|
||||||
|
break;
|
||||||
|
case 'f':
|
||||||
|
case 'F':
|
||||||
|
_segments[i] = SIGF;
|
||||||
|
break;
|
||||||
|
case 'g':
|
||||||
|
case 'G':
|
||||||
|
_segments[i] = SIGG;
|
||||||
|
break;
|
||||||
|
case 'h':
|
||||||
|
_segments[i] = SIGh;
|
||||||
|
break;
|
||||||
|
case 'H':
|
||||||
|
_segments[i] = SIGH;
|
||||||
|
break;
|
||||||
|
case 'i':
|
||||||
|
case 'I':
|
||||||
|
_segments[i] = SIGI;
|
||||||
|
break;
|
||||||
|
case 'j':
|
||||||
|
case 'J':
|
||||||
|
_segments[i] = SIGJ;
|
||||||
|
break;
|
||||||
|
case 'l':
|
||||||
|
_segments[i] = SIGl;
|
||||||
|
break;
|
||||||
|
case 'L':
|
||||||
|
_segments[i] = SIGL;
|
||||||
|
break;
|
||||||
|
case 'n':
|
||||||
|
case 'N':
|
||||||
|
_segments[i] = SIGN;
|
||||||
|
break;
|
||||||
|
case 'o':
|
||||||
|
_segments[i] = SIGo;
|
||||||
|
break;
|
||||||
|
case 'O':
|
||||||
|
_segments[i] = SIGO;
|
||||||
|
break;
|
||||||
|
case 'p':
|
||||||
|
case 'P':
|
||||||
|
_segments[i] = SIGP;
|
||||||
|
break;
|
||||||
|
case 'r':
|
||||||
|
case 'R':
|
||||||
|
_segments[i] = SIGR;
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
case 'S':
|
||||||
|
_segments[i] = SIGS;
|
||||||
|
break;
|
||||||
|
case 't':
|
||||||
|
case 'T':
|
||||||
|
_segments[i] = SIGT;
|
||||||
|
break;
|
||||||
|
case 'u':
|
||||||
|
case 'U':
|
||||||
|
_segments[i] = SIGU;
|
||||||
|
break;
|
||||||
|
case 'v':
|
||||||
|
case 'V':
|
||||||
|
_segments[i] = SIGV;
|
||||||
|
break;
|
||||||
|
case 'x':
|
||||||
|
case 'X':
|
||||||
|
_segments[i] = SIGX;
|
||||||
|
break;
|
||||||
|
case 'y':
|
||||||
|
case 'Y':
|
||||||
|
_segments[i] = SIGY;
|
||||||
|
break;
|
||||||
|
case '-':
|
||||||
|
_segments[i] = MINUS;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
_segments[i] = INVLD;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if( (1 << i) & dp ) _segments[i] |= 1;
|
||||||
|
}
|
||||||
|
if(string[i] == '\0') for(; i < 8; i++) _segments[i]&=SEG_DP;
|
||||||
|
}
|
83
CL56.h
Normal file
83
CL56.h
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <avr/io.h>
|
||||||
|
#include "shiftreg.h"
|
||||||
|
|
||||||
|
#define SEG_A 0b10000000
|
||||||
|
#define SEG_B 0b01000000
|
||||||
|
#define SEG_C 0b00100000
|
||||||
|
#define SEG_D 0b00010000
|
||||||
|
#define SEG_E 0b00001000
|
||||||
|
#define SEG_F 0b00000100
|
||||||
|
#define SEG_G 0b00000010
|
||||||
|
#define SEG_DP 0b00000001
|
||||||
|
|
||||||
|
class DualCl56
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
static constexpr uint8_t COLEN_A = 0b00000010;
|
||||||
|
static constexpr uint8_t COLEN_B = 0b00100000;
|
||||||
|
static constexpr uint8_t DP_A = 0b00000000;
|
||||||
|
static constexpr uint8_t DP_B = 0b00000001;
|
||||||
|
static constexpr uint8_t DP_C = 0b00000100;
|
||||||
|
static constexpr uint8_t DP_D = 0b00001000;
|
||||||
|
static constexpr uint8_t DP_E = 0b00000000;
|
||||||
|
static constexpr uint8_t DP_F = 0b00010000;
|
||||||
|
static constexpr uint8_t DP_G = 0b01000000;
|
||||||
|
static constexpr uint8_t DP_H = 0b10000000;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
static constexpr uint8_t ZERO = SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F;
|
||||||
|
static constexpr uint8_t ONE = SEG_B | SEG_C;
|
||||||
|
static constexpr uint8_t TOW = SEG_A | SEG_B | SEG_G | SEG_E | SEG_D;
|
||||||
|
static constexpr uint8_t THREE = SEG_A | SEG_B | SEG_C | SEG_D | SEG_G;
|
||||||
|
static constexpr uint8_t FOUR = SEG_B | SEG_C | SEG_F | SEG_G;
|
||||||
|
static constexpr uint8_t FIVE =SEG_A | SEG_C | SEG_D | SEG_F | SEG_G;
|
||||||
|
static constexpr uint8_t SIX = SEG_A | SEG_C | SEG_D | SEG_E | SEG_F | SEG_G;
|
||||||
|
static constexpr uint8_t SEVEN= SEG_A | SEG_B | SEG_C;
|
||||||
|
static constexpr uint8_t EIGT = SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F | SEG_G;
|
||||||
|
static constexpr uint8_t NINE = SEG_A | SEG_B | SEG_C | SEG_D | SEG_F | SEG_G;
|
||||||
|
static constexpr uint8_t MINUS = SEG_G;
|
||||||
|
static constexpr uint8_t SIGA = SEG_A | SEG_B | SEG_C | SEG_E | SEG_F | SEG_G;
|
||||||
|
static constexpr uint8_t SIGB = SEG_F | SEG_E | SEG_D | SEG_C | SEG_G;
|
||||||
|
static constexpr uint8_t SIGC = SEG_A | SEG_D | SEG_E | SEG_F;
|
||||||
|
static constexpr uint8_t SIGc = SEG_G | SEG_D | SEG_E;
|
||||||
|
static constexpr uint8_t SIGD = SEG_B | SEG_C | SEG_D | SEG_G | SEG_E;
|
||||||
|
static constexpr uint8_t SIGE = SEG_A | SEG_D | SEG_E | SEG_F | SEG_G;
|
||||||
|
static constexpr uint8_t SIGF = SEG_A | SEG_E | SEG_F | SEG_G;
|
||||||
|
static constexpr uint8_t SIGG = NINE;
|
||||||
|
static constexpr uint8_t SIGH = SEG_B | SEG_C | SEG_E | SEG_F | SEG_G;
|
||||||
|
static constexpr uint8_t SIGh = SEG_D | SEG_C | SEG_E | SEG_F | SEG_G;
|
||||||
|
static constexpr uint8_t SIGI = SEG_E;
|
||||||
|
static constexpr uint8_t SIGJ = SEG_B | SEG_C | SEG_D;
|
||||||
|
static constexpr uint8_t SIGL = SEG_F | SEG_E | SEG_D;
|
||||||
|
static constexpr uint8_t SIGl = SEG_F | SEG_E;
|
||||||
|
static constexpr uint8_t SIGN = SEG_C | SEG_E | SEG_G;
|
||||||
|
static constexpr uint8_t SIGO = ZERO;
|
||||||
|
static constexpr uint8_t SIGo = SEG_E | SEG_G | SEG_C | SEG_D;
|
||||||
|
static constexpr uint8_t SIGP = SEG_A | SEG_B | SEG_G | SEG_F | SEG_E;
|
||||||
|
static constexpr uint8_t SIGR = SEG_G | SEG_E;
|
||||||
|
static constexpr uint8_t SIGS = SEG_A | SEG_C | SEG_D | SEG_F | SEG_G;
|
||||||
|
static constexpr uint8_t SIGT = SEG_F | SEG_E | SEG_C | SEG_D;
|
||||||
|
static constexpr uint8_t SIGU = SEG_B | SEG_C | SEG_D | SEG_E | SEG_F;
|
||||||
|
static constexpr uint8_t SIGV = SIGU;
|
||||||
|
static constexpr uint8_t SIGX = SIGH;
|
||||||
|
static constexpr uint8_t SIGY = SEG_F | SEG_B | SEG_G | SEG_E;
|
||||||
|
static constexpr uint8_t INVLD = SEG_A | SEG_D;
|
||||||
|
|
||||||
|
uint8_t _currentLit = 0;
|
||||||
|
uint8_t _segments[8] = {SEG_A, SEG_B, SEG_C, SEG_D, SEG_E, SEG_G, SEG_DP, FIVE};
|
||||||
|
|
||||||
|
ShiftReg<16>* _shiftReg;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
DualCl56(ShiftReg<16>* shiftReg);
|
||||||
|
|
||||||
|
void tick();
|
||||||
|
|
||||||
|
void setString(const char* string, const uint8_t dp = 0);
|
||||||
|
};
|
||||||
|
|
59
CMakeLists.txt
Normal file
59
CMakeLists.txt
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
## A simple CMake file to compile an Arduino project.
|
||||||
|
## Adjust the settings according to your board.
|
||||||
|
## The settings here work for the Arduino Uno, Rev. 3.
|
||||||
|
|
||||||
|
# Project name
|
||||||
|
project(SensorDisplay)
|
||||||
|
|
||||||
|
# CMake version
|
||||||
|
cmake_minimum_required(VERSION 2.6)
|
||||||
|
|
||||||
|
# Options
|
||||||
|
# Adjust to your board
|
||||||
|
set(MCU "atmega328p" CACHE STRING "Processor Type")
|
||||||
|
set(CPU_SPEED "16000000" CACHE STRING "Speed of the CPU")
|
||||||
|
set(PORT "/dev/ttyUSB0" CACHE STRING "USB Port")
|
||||||
|
set(PORT_SPEED "57600" CACHE STRING "Serial Port Speed")
|
||||||
|
set(PROGRAMMER "stk500v1" CACHE STRING "Programmer Type")
|
||||||
|
set(COMPILE_FLAGS "" CACHE STRING "Additional Compiler Flags")
|
||||||
|
|
||||||
|
# Set own source files
|
||||||
|
# Simply list all your C / C++ source (not header!) files here
|
||||||
|
set(SRC_FILES main.cpp serial.cpp W433DataReciver.cpp CL56.cpp ds1302.cpp)
|
||||||
|
|
||||||
|
# Compiler suite specification
|
||||||
|
set(CMAKE_C_COMPILER /usr/bin/avr-gcc)
|
||||||
|
set(CMAKE_CXX_COMPILER /usr/bin/avr-g++)
|
||||||
|
set(CMAKE_OBJCOPY /usr/bin/avr-objcopy)
|
||||||
|
set(CMAKE_OBJDUMP /usr/bin/avr-objdump)
|
||||||
|
set(CMAKE_RANLIB /usr/bin/avr-ranlib)
|
||||||
|
set(CMAKE_LINKER /usr/bin/avr-ld)
|
||||||
|
|
||||||
|
# Compiler flags
|
||||||
|
add_definitions(-mmcu=${MCU} -DF_CPU=${CPU_SPEED})
|
||||||
|
add_definitions(-s -c -g -Os -flto -Wall -std=c++17 -fno-strict-aliasing)
|
||||||
|
add_definitions(-fno-exceptions -ffunction-sections -fdata-sections)
|
||||||
|
|
||||||
|
# Linker flags
|
||||||
|
set(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") # remove -rdynamic for C
|
||||||
|
set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "") # remove -rdynamic for CXX
|
||||||
|
set(CMAKE_EXE_LINKER_FLAGS "-Os -Wl,--gc-sections -mmcu=${MCU}")
|
||||||
|
|
||||||
|
add_executable(${PROJECT_NAME} ${ARDUINO_CORE_SRC} ${SRC_FILES})
|
||||||
|
|
||||||
|
find_program(AR_AVRDUDE NAMES avrdude PATHS /usr/bin NO_DEFAULT_PATH)
|
||||||
|
|
||||||
|
find_program(AR_AVRSIZE NAMES avr-size PATHS /usr/bin NO_DEFAULT_PATH)
|
||||||
|
|
||||||
|
add_custom_target(download
|
||||||
|
COMMAND ${CMAKE_OBJCOPY} -j .text -j .data -O ihex ${PROJECT_NAME} ${PROJECT_NAME}.hex
|
||||||
|
COMMAND ${AR_AVRSIZE} -C ${PROJECT_NAME}
|
||||||
|
COMMAND ${AR_AVRDUDE} -v -p ${MCU} -c ${PROGRAMMER} -P /dev/ttyUSB0 -b 57600 -D -U flash:w:${PROJECT_NAME}.hex
|
||||||
|
DEPENDS ${PROJECT_NAME}
|
||||||
|
)
|
||||||
|
|
||||||
|
add_custom_target(export
|
||||||
|
COMMAND ${CMAKE_OBJCOPY} -j .text -j .data -O ihex ${PROJECT_NAME} ${PROJECT_NAME}.hex
|
||||||
|
COMMAND ${AR_AVRSIZE} -C ${PROJECT_NAME}
|
||||||
|
DEPENDS ${PROJECT_NAME}
|
||||||
|
)
|
231
W433DataReciver.cpp
Normal file
231
W433DataReciver.cpp
Normal file
@ -0,0 +1,231 @@
|
|||||||
|
#include "W433DataReciver.h"
|
||||||
|
#include "writepin.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <avr/io.h>
|
||||||
|
#include <util/delay.h>
|
||||||
|
#include <avr/interrupt.h>
|
||||||
|
#include "serial.h"
|
||||||
|
|
||||||
|
W433DataReciver* W433DataReciver::instance = nullptr;
|
||||||
|
|
||||||
|
W433DataReciver::W433DataReciver(volatile unsigned char* const port , const unsigned char pin, volatile uint16_t * timerRegister, volatile uint8_t* const timerOverflowRegister, void (* const packetCallback)(uint32_t, void*), void* const userData, void (*errorCodeHandler)(uint8_t, void*) ):
|
||||||
|
_port(port), _pin(pin), _timerRegister(timerRegister), _timerOverflowRegister(timerOverflowRegister), _packetCallback(packetCallback), _errorCodeHandler(errorCodeHandler), _userData(userData)
|
||||||
|
{
|
||||||
|
instance = this;
|
||||||
|
for(uint8_t i = 0; i < 33; i++) timesBuffer[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
W433DataReciver::~W433DataReciver()
|
||||||
|
{
|
||||||
|
instance = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void W433DataReciver::staticInterrupt()
|
||||||
|
{
|
||||||
|
if(instance != nullptr) instance->interrupt();
|
||||||
|
}
|
||||||
|
|
||||||
|
int8_t W433DataReciver::reciveBit(uint8_t index)
|
||||||
|
{
|
||||||
|
if(
|
||||||
|
timesBuffer[index] < 0 &&
|
||||||
|
isTime(timesBuffer[index+1], SMALL_TIME, true, SMALL_TIME_TOLERANCE) &&
|
||||||
|
isTime(timesBuffer[index+2], LARGE_TIME, false, LARGE_TIME_TOLERANCE) //&&
|
||||||
|
//isTime(timesBuffer[index+3], SMALL_TIME, true, SMALL_TIME_TOLERANCE)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else if(
|
||||||
|
timesBuffer[index] < 0 &&
|
||||||
|
isTime(timesBuffer[index+1], LARGE_TIME, true, LARGE_TIME_TOLERANCE) &&
|
||||||
|
isTime(timesBuffer[index+2], SMALL_TIME, false, SMALL_TIME_TOLERANCE) //&&
|
||||||
|
//isTime(timesBuffer[index+3], SMALL_TIME, true, SMALL_TIME_TOLERANCE)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void W433DataReciver::waitForReciveIdle(const uint16_t timeoutMs)
|
||||||
|
{
|
||||||
|
uint16_t counter = 0;
|
||||||
|
while(true)
|
||||||
|
{
|
||||||
|
while(counter < timeoutMs && state != LOOKING_FOR_SYNC)
|
||||||
|
{
|
||||||
|
_delay_ms(1);
|
||||||
|
++counter;
|
||||||
|
}
|
||||||
|
_delay_ms(500);
|
||||||
|
counter+=500;
|
||||||
|
if(state == LOOKING_FOR_SYNC || counter >= timeoutMs) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool W433DataReciver::isTime(int16_t input, const uint16_t time, const bool state, const uint16_t tollerance)
|
||||||
|
{
|
||||||
|
if((state && input < 0) || (!state && input > 0)) return false;
|
||||||
|
input = abs(input);
|
||||||
|
return input < (int16_t)(time+tollerance) && input > (int16_t)(time-tollerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool W433DataReciver::reciveSync(const uint16_t elapsedTime)
|
||||||
|
{
|
||||||
|
if(elapsedTime < SYNC_TIME+SYNC_TIME_TOLERANCE && elapsedTime > SYNC_TIME-SYNC_TIME_TOLERANCE)
|
||||||
|
{
|
||||||
|
++syncCount;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(syncCount > 4 && syncFailCount < 3) ++syncFailCount;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//if(syncCount > 7) error(ERR_SYNC_FAIL);
|
||||||
|
setState(LOOKING_FOR_SYNC);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(syncCount > 10) return true;
|
||||||
|
else return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool W433DataReciver::recivedByte(const uint16_t elapsedTime)
|
||||||
|
{
|
||||||
|
timesBuffer[timesBufferIndex] = readPin(_port, _pin) ? 0-elapsedTime : elapsedTime;
|
||||||
|
++timesBufferIndex;
|
||||||
|
return timesBufferIndex == 32;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t W433DataReciver::assmbleByte()
|
||||||
|
{
|
||||||
|
uint8_t byte = 0;
|
||||||
|
for(uint8_t i = 0; i < 8; ++i)
|
||||||
|
{
|
||||||
|
int8_t bit = reciveBit(i*4);
|
||||||
|
if(bit >= 0) byte = byte | (bit << (7-i));
|
||||||
|
else
|
||||||
|
{
|
||||||
|
setState(LOOKING_FOR_SYNC);
|
||||||
|
error(ERR_BYTE_ASM);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
timesBufferIndex = 0;
|
||||||
|
return byte;
|
||||||
|
}
|
||||||
|
|
||||||
|
void W433DataReciver::error(const uint8_t errorCode)
|
||||||
|
{
|
||||||
|
if(_errorCodeHandler != nullptr) (*_errorCodeHandler)(errorCode, _userData);
|
||||||
|
}
|
||||||
|
|
||||||
|
void W433DataReciver::setState(const uint8_t stateIn)
|
||||||
|
{
|
||||||
|
TIMSK2 = stateIn == LOOKING_FOR_SYNC;
|
||||||
|
state = stateIn;
|
||||||
|
timesBufferIndex = 0;
|
||||||
|
packetIndex = 0;
|
||||||
|
syncCount = 0;
|
||||||
|
syncFailCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void W433DataReciver::interrupt()
|
||||||
|
{
|
||||||
|
uint16_t elapsedTime = polarity*(((*_timerOverflowRegister & 0x01) ? *_timerRegister+(UINT16_MAX - previousTime) : *_timerRegister - previousTime)/TICKS_PER_US);
|
||||||
|
|
||||||
|
if(elapsedTime < DISCARD_TIME)
|
||||||
|
{
|
||||||
|
if(timesBufferIndex > 0 && elapsedTime + abs(timesBuffer[timesBufferIndex-1]) < LARGE_TIME+LARGE_TIME_TOLERANCE)
|
||||||
|
{
|
||||||
|
previousTime = *_timerRegister - elapsedTime - abs(timesBuffer[timesBufferIndex-1]);
|
||||||
|
timesBufferIndex-=1;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
previousTime = *_timerRegister;
|
||||||
|
*_timerOverflowRegister = *_timerOverflowRegister | 0x01;
|
||||||
|
|
||||||
|
if(state == LOOKING_FOR_SYNC && reciveSync(elapsedTime))
|
||||||
|
{
|
||||||
|
setState(LOOKING_FOR_SYNC_END);
|
||||||
|
}
|
||||||
|
else if(state == LOOKING_FOR_SYNC_END)
|
||||||
|
{
|
||||||
|
if(elapsedTime > SYNC_TIME + SYNC_END_TIME_TOLERANCE)
|
||||||
|
{
|
||||||
|
if(elapsedTime < LARGE_TIME - LARGE_TIME_TOLERANCE)
|
||||||
|
{
|
||||||
|
setState(LOOKING_FOR_SYNC);
|
||||||
|
error(ERR_NO_SYNC_END);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
timesBuffer[0] = -LARGE_TIME;
|
||||||
|
setState(LOOKING_FOR_SIGNATURE);
|
||||||
|
++timesBufferIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(state == LOOKING_FOR_SIGNATURE)
|
||||||
|
{
|
||||||
|
if(recivedByte(elapsedTime))
|
||||||
|
{
|
||||||
|
uint8_t recivedSignature = assmbleByte();
|
||||||
|
if( recivedSignature == signature) setState(RECVING_PACKET);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
error(ERR_WRONG_SIG);
|
||||||
|
setState(LOOKING_FOR_SYNC);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if( state == RECVING_PACKET )
|
||||||
|
{
|
||||||
|
|
||||||
|
if(recivedByte(elapsedTime))
|
||||||
|
{
|
||||||
|
uint8_t packetByte = assmbleByte();
|
||||||
|
|
||||||
|
packet = packet | ((uint32_t)packetByte) << ((3-packetIndex)*8);
|
||||||
|
++packetIndex;
|
||||||
|
if(packetIndex > 3)
|
||||||
|
{
|
||||||
|
packetIndex = 0;
|
||||||
|
timesBufferIndex = 0;
|
||||||
|
setState(RECVING_PACKET_CHECKSUM);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(state == RECVING_PACKET_CHECKSUM)
|
||||||
|
{
|
||||||
|
if(recivedByte(elapsedTime))
|
||||||
|
{
|
||||||
|
uint8_t recivedChecksum = assmbleByte();
|
||||||
|
|
||||||
|
volatile uint8_t* buffer = reinterpret_cast<volatile uint8_t*>(&packet);
|
||||||
|
|
||||||
|
uint8_t computedChecksum = 0;
|
||||||
|
for(uint8_t j = 0; j < sizeof(packet); j++) for(uint8_t i = 0; i < 8; i++) computedChecksum = computedChecksum + ((buffer[j] & ( 1 << (8 - i))) >> (8 - i));
|
||||||
|
//for(uint8_t j = 0; j < sizeof(packet); j++) for(uint8_t i = 0; i < 8; i++) computedChecksum = computedChecksum + (buffer[j] & ( 1 << (8 - i)));
|
||||||
|
|
||||||
|
if(computedChecksum == recivedChecksum)
|
||||||
|
{
|
||||||
|
#ifdef USE_RINGBUFFER
|
||||||
|
_ringBuffer.write(const_cast<uint8_t*>(buffer), sizeof(packet));
|
||||||
|
#endif
|
||||||
|
if(_packetCallback != nullptr)(*_packetCallback)(packet, _userData);
|
||||||
|
}
|
||||||
|
else error(ERR_CHECKSUM);
|
||||||
|
packet = 0;
|
||||||
|
setState(LOOKING_FOR_SYNC);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef USE_RINGBUFFER
|
||||||
|
RingBuffer<W433DataReciver::RINGBUFFER_LENGTH, uint8_t>* W433DataReciver::getRingBuffer()
|
||||||
|
{
|
||||||
|
return &_ringBuffer;
|
||||||
|
}
|
||||||
|
#endif
|
94
W433DataReciver.h
Normal file
94
W433DataReciver.h
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "ringbuffer.h"
|
||||||
|
|
||||||
|
//#define USE_RINGBUFFER
|
||||||
|
|
||||||
|
class W433DataReciver
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
static constexpr uint8_t RINGBUFFER_LENGTH = 32;
|
||||||
|
|
||||||
|
//errors
|
||||||
|
static constexpr uint8_t ERR_SYNC_FAIL = 1;
|
||||||
|
static constexpr uint8_t ERR_NO_SYNC_END = 2;
|
||||||
|
static constexpr uint8_t ERR_BYTE_ASM = 3;
|
||||||
|
static constexpr uint8_t ERR_WRONG_SIG = 4;
|
||||||
|
static constexpr uint8_t ERR_CHECKSUM = 5;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
static W433DataReciver* instance;
|
||||||
|
|
||||||
|
//constants
|
||||||
|
static constexpr uint8_t CLOCK_DEVIDER = 1;
|
||||||
|
static constexpr uint16_t LARGE_TIME = 2000;
|
||||||
|
static constexpr uint16_t SMALL_TIME = 500;
|
||||||
|
static constexpr uint16_t SYNC_TIME = 800;
|
||||||
|
static constexpr uint8_t SYNC_TIME_TOLERANCE = SYNC_TIME*0.20;
|
||||||
|
static constexpr uint16_t SYNC_END_TIME_TOLERANCE = SYNC_TIME*0.50;
|
||||||
|
static constexpr uint16_t LARGE_TIME_TOLERANCE = LARGE_TIME*0.30;
|
||||||
|
static constexpr uint8_t SMALL_TIME_TOLERANCE = SMALL_TIME*0.30;
|
||||||
|
static constexpr uint16_t DISCARD_TIME = SMALL_TIME*0.6;
|
||||||
|
static constexpr uint16_t TICKS_PER_US = (F_CPU) / (1000000*CLOCK_DEVIDER) ;
|
||||||
|
static constexpr uint8_t signature = 0xA5;
|
||||||
|
|
||||||
|
static constexpr int8_t polarity = 1;
|
||||||
|
|
||||||
|
static constexpr uint8_t LOOKING_FOR_SYNC = 0;
|
||||||
|
static constexpr uint8_t LOOKING_FOR_SYNC_END = 1;
|
||||||
|
static constexpr uint8_t LOOKING_FOR_SIGNATURE = 2;
|
||||||
|
static constexpr uint8_t RECVING_PACKET = 3;
|
||||||
|
static constexpr uint8_t RECVING_PACKET_CHECKSUM = 4;
|
||||||
|
|
||||||
|
//variables
|
||||||
|
volatile unsigned char *_port;
|
||||||
|
unsigned char _pin;
|
||||||
|
|
||||||
|
volatile uint16_t *_timerRegister;
|
||||||
|
volatile uint8_t *_timerOverflowRegister;
|
||||||
|
|
||||||
|
#ifdef USE_RINGBUFFER
|
||||||
|
RingBuffer<RINGBUFFER_LENGTH, uint8_t> _ringBuffer;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
volatile uint16_t previousTime = 0;
|
||||||
|
volatile uint8_t timesBufferIndex = 0;
|
||||||
|
volatile int16_t timesBuffer[33];
|
||||||
|
|
||||||
|
volatile uint8_t packetIndex = 0;
|
||||||
|
volatile uint32_t packet = 0;
|
||||||
|
|
||||||
|
void (* const _packetCallback)(uint32_t, void*);
|
||||||
|
void (* const _errorCodeHandler)(uint8_t, void*);
|
||||||
|
void* const _userData;
|
||||||
|
|
||||||
|
volatile uint8_t syncCount = 0;
|
||||||
|
volatile uint8_t syncFailCount = 0;
|
||||||
|
volatile uint8_t state = 0;
|
||||||
|
|
||||||
|
//private functions
|
||||||
|
int8_t reciveBit(uint8_t index);
|
||||||
|
|
||||||
|
inline uint8_t assmbleByte();
|
||||||
|
inline void setState(const uint8_t stateIn);
|
||||||
|
inline bool recivedByte(const uint16_t elapsedTime);
|
||||||
|
inline bool reciveSync(const uint16_t elapsedTime);
|
||||||
|
|
||||||
|
inline void error(const uint8_t errorCode);
|
||||||
|
|
||||||
|
static inline bool isTime(int16_t input, const uint16_t time, const bool state = true, const uint16_t tollerance = 100);
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
W433DataReciver(volatile unsigned char* const port , const unsigned char pin, volatile uint16_t * timerRegister, volatile uint8_t* const timerOverflowRegister, void (*packetCallback)(uint32_t, void*) = nullptr, void* userData = nullptr, void (*errorCodeHandler)(uint8_t, void*) = nullptr );
|
||||||
|
~W433DataReciver();
|
||||||
|
static void initTimer();
|
||||||
|
static void staticInterrupt();
|
||||||
|
void waitForReciveIdle(const uint16_t timeoutMs = 10000);
|
||||||
|
void interrupt();
|
||||||
|
#ifdef USE_RINGBUFFER
|
||||||
|
RingBuffer<RINGBUFFER_LENGTH, uint8_t>* getRingBuffer();
|
||||||
|
#endif
|
||||||
|
};
|
9
bitrep.h
Normal file
9
bitrep.h
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
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",
|
||||||
|
};
|
48
buttons.h
Normal file
48
buttons.h
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <avr/io.h>
|
||||||
|
#include "writepin.h"
|
||||||
|
|
||||||
|
class Buttons
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
static constexpr uint8_t PRESSED = 0;
|
||||||
|
static constexpr uint8_t RELEASED = 2;
|
||||||
|
static constexpr uint8_t LONG_PRESSED = 1;
|
||||||
|
static constexpr uint8_t LONG_RELEASED= 3;
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
volatile uint8_t * const pinReg = &PIND;
|
||||||
|
static constexpr uint16_t usPerTick = 1000;
|
||||||
|
static constexpr uint8_t button[] = { PD6, PD7 };
|
||||||
|
static constexpr uint8_t buttonsAmount = sizeof(button);
|
||||||
|
uint32_t buttonCount[buttonsAmount] = {};
|
||||||
|
|
||||||
|
void* _userData;
|
||||||
|
void (*_eventHandler)(uint8_t index, uint8_t type, void* data);
|
||||||
|
|
||||||
|
public:
|
||||||
|
Buttons(void (*eventHandler)(uint8_t index, uint8_t type, void* data), void* userData = nullptr): _userData(userData), _eventHandler(eventHandler){}
|
||||||
|
void tick();
|
||||||
|
};
|
||||||
|
|
||||||
|
void Buttons::tick()
|
||||||
|
{
|
||||||
|
for(uint8_t i = 0; i < buttonsAmount; ++i)
|
||||||
|
{
|
||||||
|
if(readPin(pinReg, button[i]) == true)
|
||||||
|
{
|
||||||
|
if(buttonCount[i]*usPerTick >= 1000000) _eventHandler(i, LONG_RELEASED, _userData);
|
||||||
|
else if(buttonCount[i]*usPerTick >= 30000)_eventHandler(i, RELEASED, _userData);
|
||||||
|
buttonCount[i] = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(buttonCount[i]*usPerTick == 30000) _eventHandler(i, PRESSED, _userData);
|
||||||
|
else if(buttonCount[i]*usPerTick == 1000000) _eventHandler(i, LONG_PRESSED, _userData);
|
||||||
|
++buttonCount[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
85
ds1302.cpp
Normal file
85
ds1302.cpp
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
#include "ds1302.h"
|
||||||
|
#include "writepin.h"
|
||||||
|
|
||||||
|
DS1302::DS1302(volatile unsigned char *port, volatile unsigned char *pinReg, volatile unsigned char *ddrReg, const unsigned char pinIO, const unsigned char pinCE, const unsigned char _pinSCLK):
|
||||||
|
_port(port), _pinReg(pinReg), _ddrReg(ddrReg), _pinIO(pinIO), _pinCE(pinCE), _pinSCLK(_pinSCLK)
|
||||||
|
{
|
||||||
|
*_ddrReg |= (1<<_pinCE) | (1<<_pinSCLK) | (1<<_pinIO);
|
||||||
|
write(REG_WP, 0x00);
|
||||||
|
uint8_t reg = read(REG_SEC);
|
||||||
|
write(REG_SEC, reg & ~0b10000000);
|
||||||
|
write(REG_WP, 0xFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DS1302::write(uint8_t addr, uint8_t value)
|
||||||
|
{
|
||||||
|
setBit(_ddrReg, _pinIO, true);
|
||||||
|
writePin(_port, _pinCE, true);
|
||||||
|
for(uint8_t i = 0; i < 8; ++i)
|
||||||
|
{
|
||||||
|
writePin(_port, _pinSCLK, false);
|
||||||
|
writePin(_port, _pinIO, addr & (1<<i));
|
||||||
|
writePin(_port, _pinSCLK, true);
|
||||||
|
}
|
||||||
|
for(uint8_t i = 0; i < 8; ++i)
|
||||||
|
{
|
||||||
|
writePin(_port, _pinSCLK, false);
|
||||||
|
writePin(_port, _pinIO, value & (1<<i));
|
||||||
|
writePin(_port, _pinSCLK, true);
|
||||||
|
}
|
||||||
|
writePin(_port, _pinSCLK, false);
|
||||||
|
writePin(_port, _pinCE, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t DS1302::read(uint8_t addr)
|
||||||
|
{
|
||||||
|
setBit(_ddrReg, _pinIO, true);
|
||||||
|
writePin(_port, _pinCE, true);
|
||||||
|
for(uint8_t i = 0; i < 8; ++i)
|
||||||
|
{
|
||||||
|
writePin(_port, _pinSCLK, false);
|
||||||
|
writePin(_port, _pinIO, (addr | 1) & (1<<i));
|
||||||
|
writePin(_port, _pinSCLK, true);
|
||||||
|
}
|
||||||
|
setBit(_ddrReg, _pinIO, false);
|
||||||
|
writePin(_port, _pinSCLK, false);
|
||||||
|
uint8_t bits = 0;
|
||||||
|
for(uint8_t i = 0; i < 8; ++i)
|
||||||
|
{
|
||||||
|
writePin(_port, _pinSCLK, true);
|
||||||
|
if(readPin(_pinReg, _pinIO)) bits |= (1<<i);
|
||||||
|
writePin(_port, _pinSCLK, false);
|
||||||
|
}
|
||||||
|
writePin(_port, _pinCE, false);
|
||||||
|
return bits;
|
||||||
|
}
|
||||||
|
|
||||||
|
DS1302::Timeval DS1302::getTime()
|
||||||
|
{
|
||||||
|
Timeval time;
|
||||||
|
uint8_t reg = read(REG_SEC);
|
||||||
|
time.sec = (reg & 0b00001111) + 10*((reg & 0b01110000)>>4);
|
||||||
|
reg = read(REG_MIN);
|
||||||
|
time.min = (reg & 0b00001111) + 10*((reg & 0b01110000)>>4);
|
||||||
|
reg = read(REG_HOUR);
|
||||||
|
time.hour = (reg & 0b00001111) + 10*((reg & 0b00110000)>>4);
|
||||||
|
reg = read(REG_DAY);
|
||||||
|
time.day = (reg & 0b00001111) + 10*((reg & 0b00110000)>>4);
|
||||||
|
reg = read(REG_MONTH);
|
||||||
|
time.month = (reg & 0b00001111) + 10*((reg & 0b00110000)>>4);
|
||||||
|
reg = read(REG_YEAR);
|
||||||
|
time.year = (reg & 0b00001111) + 10*((reg & 0b11110000)>>4) + EPOCH;
|
||||||
|
return time;
|
||||||
|
}
|
||||||
|
void DS1302::setTime(const Timeval& in)
|
||||||
|
{
|
||||||
|
write(REG_WP, 0x00);
|
||||||
|
write(REG_SEC, ((in.sec / 10) << 4) | (in.sec % 10) );
|
||||||
|
write(REG_MIN, ((in.min / 10) << 4) | (in.min % 10) );
|
||||||
|
write(REG_HOUR, ((in.hour / 10) << 4) | (in.hour % 10));
|
||||||
|
write(REG_DAY, ((in.day / 10) << 4) | (in.day % 10));
|
||||||
|
write(REG_MONTH,((in.month / 10) << 4) | (in.month % 10));
|
||||||
|
uint8_t year = in.year - EPOCH;
|
||||||
|
write(REG_YEAR,((year / 10) << 4) | (year % 10));
|
||||||
|
write(REG_WP, 0xFF);
|
||||||
|
}
|
47
ds1302.h
Normal file
47
ds1302.h
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
class DS1302
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef struct Timeval
|
||||||
|
{
|
||||||
|
uint8_t sec;
|
||||||
|
uint8_t min;
|
||||||
|
uint8_t hour;
|
||||||
|
uint8_t day;
|
||||||
|
uint8_t month;
|
||||||
|
uint16_t year;
|
||||||
|
} Timeval;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
static constexpr uint16_t EPOCH = 2000;
|
||||||
|
|
||||||
|
static constexpr uint8_t REG_SEC = 0x80;
|
||||||
|
static constexpr uint8_t REG_MIN = 0x82;
|
||||||
|
static constexpr uint8_t REG_HOUR = 0x84;
|
||||||
|
static constexpr uint8_t REG_DAY = 0x86;
|
||||||
|
static constexpr uint8_t REG_MONTH= 0x88;
|
||||||
|
static constexpr uint8_t REG_YEAR = 0x8C;
|
||||||
|
static constexpr uint8_t REG_WP = 0x8E;
|
||||||
|
|
||||||
|
static constexpr int8_t writeRegisterOffset = -1;
|
||||||
|
|
||||||
|
volatile unsigned char *_port;
|
||||||
|
volatile unsigned char *_pinReg;
|
||||||
|
volatile unsigned char *_ddrReg;
|
||||||
|
const unsigned char _pinIO;
|
||||||
|
const unsigned char _pinCE;
|
||||||
|
const unsigned char _pinSCLK;
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
DS1302(volatile unsigned char *port, volatile unsigned char *pinReg, volatile unsigned char *ddrReg, const unsigned char pinIO, const unsigned char pinCE, const unsigned char pinSCLK);
|
||||||
|
|
||||||
|
void write(const uint8_t addr,const uint8_t value);
|
||||||
|
uint8_t read(const uint8_t addr);
|
||||||
|
|
||||||
|
Timeval getTime();
|
||||||
|
void setTime(const Timeval& in);
|
||||||
|
};
|
51
eeprom.h
Normal file
51
eeprom.h
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T> void EEPROM_write_class(uint16_t address, T& in)
|
||||||
|
{
|
||||||
|
EEPROM_write_string( address, reinterpret_cast<char*>(&in), sizeof(in));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T> T EEPROM_read_class(uint16_t address)
|
||||||
|
{
|
||||||
|
char data[sizeof(T)];
|
||||||
|
EEPROM_read_string( address, data, sizeof(T) );
|
||||||
|
return *reinterpret_cast<T*>(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T> void EEPROM_read_class(uint16_t address, T* in)
|
||||||
|
{
|
||||||
|
EEPROM_read_string( address, reinterpret_cast<char*>(in), sizeof(T) );
|
||||||
|
}
|
297
main.cpp
Normal file
297
main.cpp
Normal file
@ -0,0 +1,297 @@
|
|||||||
|
#include <avr/io.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <util/delay.h>
|
||||||
|
#include <avr/pgmspace.h>
|
||||||
|
#include "serial.h"
|
||||||
|
#include "writepin.h"
|
||||||
|
#include "eeprom.h"
|
||||||
|
#include "bitrep.h"
|
||||||
|
#include "watchdog.h"
|
||||||
|
#include "staticvector.h"
|
||||||
|
#include "W433DataReciver.h"
|
||||||
|
#include "CL56.h"
|
||||||
|
#include "buttons.h"
|
||||||
|
#include "ds1302.h"
|
||||||
|
#include "sensor.h"
|
||||||
|
#include "pwm.h"
|
||||||
|
|
||||||
|
#define MAX_SENSORS 32
|
||||||
|
#define COMMAND_BUFFER_SIZE 64
|
||||||
|
#define SNPRINTF_BUFFER_SIZE 96
|
||||||
|
|
||||||
|
void buttonHandler(uint8_t index, uint8_t type, void* data);
|
||||||
|
SVector<Sensor, MAX_SENSORS> sensors;
|
||||||
|
ShiftReg<16> shiftReg(&PORTB, PB3, PB2, PB1);
|
||||||
|
DS1302 clock(&PORTC, &PINC, &DDRC, PC0, PC2, PC1);
|
||||||
|
DualCl56 display(&shiftReg);
|
||||||
|
Buttons buttons(&buttonHandler);
|
||||||
|
|
||||||
|
uint8_t displaying = 0;
|
||||||
|
|
||||||
|
char buffer[SNPRINTF_BUFFER_SIZE];
|
||||||
|
|
||||||
|
volatile bool sensorsPaused=true;
|
||||||
|
|
||||||
|
ISR(INT1_vect)
|
||||||
|
{
|
||||||
|
W433DataReciver::staticInterrupt();
|
||||||
|
}
|
||||||
|
|
||||||
|
ISR(TIMER2_OVF_vect)
|
||||||
|
{
|
||||||
|
display.tick();
|
||||||
|
buttons.tick();
|
||||||
|
}
|
||||||
|
|
||||||
|
void buttonHandler(uint8_t index, uint8_t type, void* data)
|
||||||
|
{
|
||||||
|
if(index == 0 && type == Buttons::RELEASED)
|
||||||
|
{
|
||||||
|
if(++displaying < sensors.count()+2);
|
||||||
|
else displaying = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void printSensor(const Sensor& sensor, Serial* serial)
|
||||||
|
{
|
||||||
|
serial->write_p(PSTR("SENSOR TYPE: "));
|
||||||
|
serial->write(sensor.type);
|
||||||
|
serial->write_p(PSTR(" ID: "));
|
||||||
|
serial->write(sensor.id);
|
||||||
|
|
||||||
|
if(sensor.type == 1) serial->write_p(PSTR(" TEMPERATURE: "));
|
||||||
|
else if(sensor.type == 2) serial->write_p(PSTR(" HUMIDITY: "));
|
||||||
|
else serial->write_p(PSTR(" FIELD: "));
|
||||||
|
serial->write(sensor.field);
|
||||||
|
serial->putChar('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
void packetHandler(uint32_t packet, void* data)
|
||||||
|
{
|
||||||
|
Serial* serial = reinterpret_cast<Serial*>(data);
|
||||||
|
|
||||||
|
Sensor sensor;
|
||||||
|
|
||||||
|
sensor.field = packet & 0x0000FFFF;
|
||||||
|
sensor.type = packet >> 24;
|
||||||
|
sensor.id = (packet & 0x00FF0000) >> 16;
|
||||||
|
|
||||||
|
bool found = false;
|
||||||
|
for(uint8_t i = 0; i < sensors.count() && !found; ++i)
|
||||||
|
{
|
||||||
|
if(sensors[i] == sensor)
|
||||||
|
{
|
||||||
|
sensors[i] = sensor;
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!found) sensors.push_back(sensor);
|
||||||
|
|
||||||
|
if(!sensorsPaused) printSensor(sensor, serial);
|
||||||
|
}
|
||||||
|
|
||||||
|
void reciverError(uint8_t code, void* userData)
|
||||||
|
{
|
||||||
|
if(!sensorsPaused)
|
||||||
|
{
|
||||||
|
Serial* serial = reinterpret_cast<Serial*>(userData);
|
||||||
|
serial->write_p(PSTR("RECV ERROR CODE: "));
|
||||||
|
serial->write(code);
|
||||||
|
serial->putChar('\n');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline static void printHelp(Serial* serial)
|
||||||
|
{
|
||||||
|
serial->write_p(PSTR("Available Commands: \n\
|
||||||
|
help : Show this prompt.\n\
|
||||||
|
date : Show current date and time.\n\
|
||||||
|
set [yyyy] [mm] [dd] [hh] [mm] [ss] : Show current date and time.\n\
|
||||||
|
pause : pause sensor output.\n\
|
||||||
|
resume : resume sensor output.\n\
|
||||||
|
dump : Dump epprom.\n\
|
||||||
|
free : Show free ram.\n\
|
||||||
|
beep : Test buzzer.\n\
|
||||||
|
list : List sensors.\n"));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int freeRAM()
|
||||||
|
{
|
||||||
|
extern int __heap_start, *__brkval;
|
||||||
|
int v;
|
||||||
|
return (int) &v - (__brkval == 0 ? (int) &__heap_start: (int) __brkval);
|
||||||
|
}
|
||||||
|
|
||||||
|
void serialDispatch(Serial* serial, SVector<Sensor, MAX_SENSORS>* sensors)
|
||||||
|
{
|
||||||
|
if(serial->dataIsWaiting())
|
||||||
|
{
|
||||||
|
char buffer[COMMAND_BUFFER_SIZE];
|
||||||
|
unsigned int length = serial->getString(buffer, COMMAND_BUFFER_SIZE);
|
||||||
|
if(length > 2)
|
||||||
|
{
|
||||||
|
char* token = strtok(buffer, " \n");
|
||||||
|
if(strcmp(token, "date") == 0)
|
||||||
|
{
|
||||||
|
DS1302::Timeval time = clock.getTime();
|
||||||
|
snprintf(buffer, SNPRINTF_BUFFER_SIZE, "%04u.%02u.%02u %02u:%02u:%02u\n", time.year, time.month, time.day, time.hour, time.min, time.sec);
|
||||||
|
serial->write(buffer, SNPRINTF_BUFFER_SIZE);
|
||||||
|
}
|
||||||
|
else if(strcmp(token, "set") == 0)
|
||||||
|
{
|
||||||
|
char* year = strtok(NULL, " \n");
|
||||||
|
char* mon = strtok(NULL, " \n");
|
||||||
|
char* day = strtok(NULL, " \n");
|
||||||
|
char* hour = strtok(NULL, " \n");
|
||||||
|
char* min = strtok(NULL, " \n");
|
||||||
|
char* sec = strtok(NULL, " \n");
|
||||||
|
if(year != NULL && mon != NULL && day != NULL && hour != NULL && min != NULL && sec != NULL)
|
||||||
|
{
|
||||||
|
DS1302::Timeval time = {atoi(sec),atoi(min),atoi(hour),atoi(day),atoi(mon),atoi(year)};
|
||||||
|
clock.setTime(time);
|
||||||
|
serial->write_p(PSTR("date and time set\n"));
|
||||||
|
display.setString("SET");
|
||||||
|
_delay_ms(1000);
|
||||||
|
}
|
||||||
|
else serial->write_p(PSTR("usage: set [yyyy] [mm] [dd] [hh] [mm] [ss]\n"));
|
||||||
|
}
|
||||||
|
else if(strcmp(token, "pause") == 0)
|
||||||
|
{
|
||||||
|
sensorsPaused = true;
|
||||||
|
serial->write_p(PSTR("Sensors paused\n"));
|
||||||
|
}
|
||||||
|
else if(strcmp(token, "resume") == 0)
|
||||||
|
{
|
||||||
|
sensorsPaused = false;
|
||||||
|
serial->write_p(PSTR("Sensors resumed\n"));
|
||||||
|
}
|
||||||
|
else if(strcmp(token, "list") == 0)
|
||||||
|
{
|
||||||
|
serial->write_p(PSTR("Sensors:\n"));
|
||||||
|
for(uint8_t i = 0; i < sensors->count(); ++i) printSensor(sensors->at(i), serial);
|
||||||
|
serial->write('\n');
|
||||||
|
}
|
||||||
|
else if(strcmp(token, "erase") == 0)
|
||||||
|
{
|
||||||
|
for(uint16_t i = 0; i < 1024; i++) EEPROM_write_char(i, 0);
|
||||||
|
serial->write_p(PSTR("EEPROM erased\n"));
|
||||||
|
}
|
||||||
|
else if(strcmp(token, "dump") == 0)
|
||||||
|
{
|
||||||
|
for(uint16_t i = 0; i < 1024; i++)
|
||||||
|
{
|
||||||
|
if(i != 0) serial->putChar(',');
|
||||||
|
serial->write((uint16_t)EEPROM_read_char(i));
|
||||||
|
}
|
||||||
|
serial->putChar('\n');
|
||||||
|
}
|
||||||
|
else if(strcmp(token, "free") == 0)
|
||||||
|
{
|
||||||
|
serial->write_p(PSTR("Free Ram: "));
|
||||||
|
serial->write(freeRAM());
|
||||||
|
serial->write_p(PSTR(" Bytes.\n"));
|
||||||
|
}
|
||||||
|
else if(strcmp(token, "beep") == 0)
|
||||||
|
{
|
||||||
|
for(uint16_t i = 0; i < 250; ++i)
|
||||||
|
{
|
||||||
|
writePin(&PORTD, PD4, true);
|
||||||
|
_delay_us(500);
|
||||||
|
writePin(&PORTD, PD4, false);
|
||||||
|
_delay_us(1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(strcmp(token, "help") == 0)
|
||||||
|
{
|
||||||
|
printHelp(serial);
|
||||||
|
}
|
||||||
|
else serial->write_p(PSTR("Not a valid command\n"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void displayItems(const DS1302::Timeval& time)
|
||||||
|
{
|
||||||
|
switch(displaying)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
writePin(&PORTB, PB4, time.sec % 2);
|
||||||
|
snprintf(buffer, 9, " %02u%02u", time.hour, time.min);
|
||||||
|
display.setString(buffer);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
writePin(&PORTB, PB4, false);
|
||||||
|
snprintf(buffer, 9, "%02u%02u%04u", time.day, time.month, time.year);
|
||||||
|
display.setString(buffer, DualCl56::DP_B | DualCl56::DP_D);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if(displaying == 2 && sensors.count() == 0) display.setString("0 SENSOR");
|
||||||
|
else
|
||||||
|
{
|
||||||
|
writePin(&PORTB, PB4, false);
|
||||||
|
snprintf(buffer, 9, "%u%3u%4u", sensors[displaying-2].id, sensors[displaying-2].type, sensors[displaying-2].field);
|
||||||
|
display.setString(buffer, sensors[displaying-2].type == 1 || sensors[displaying-2].type == 2 ? DualCl56::DP_G : 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
DDRB = (1 << PB1) | ( 1 << PB2) | ( 1 << PB3) | ( 1 << PB4) | ( 1 << PB5);
|
||||||
|
DDRD = 1<<PD4;
|
||||||
|
PORTD |= (1<<PD6) | (1<<PD7);
|
||||||
|
|
||||||
|
TCCR2B = 1<<CS22;
|
||||||
|
TIMSK2 = 1;
|
||||||
|
|
||||||
|
TCCR1B = 1<<CS10;
|
||||||
|
|
||||||
|
EICRA = 1<<ISC10;
|
||||||
|
EIMSK = 1<<INT1;
|
||||||
|
|
||||||
|
sei();
|
||||||
|
|
||||||
|
Serial serial;
|
||||||
|
serial.write_p(PSTR("SensorDisplay v0.1 starting\n"));
|
||||||
|
|
||||||
|
DS1302::Timeval time = clock.getTime();
|
||||||
|
|
||||||
|
if(time.day == 28 && time.month == 5)
|
||||||
|
{
|
||||||
|
display.setString("HAPPY");
|
||||||
|
_delay_ms(1000);
|
||||||
|
display.setString("b-DAY");
|
||||||
|
_delay_ms(1000);
|
||||||
|
display.setString("SASA");
|
||||||
|
_delay_ms(1000);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
display.setString("HELOJANA");
|
||||||
|
_delay_ms(1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
W433DataReciver reciver(&PIND, PD3, &TCNT1, &TIFR1, &packetHandler, reinterpret_cast<void*>(&serial), &reciverError);
|
||||||
|
|
||||||
|
uint8_t deleteDate = 0;
|
||||||
|
|
||||||
|
serial.write_p(PSTR("Ready\n"));
|
||||||
|
|
||||||
|
while(true)
|
||||||
|
{
|
||||||
|
time = clock.getTime();
|
||||||
|
displayItems(time);
|
||||||
|
serialDispatch(&serial, &sensors);
|
||||||
|
if(deleteDate != time.day)
|
||||||
|
{
|
||||||
|
displaying = 0;
|
||||||
|
sensors.clear();
|
||||||
|
deleteDate = time.day;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
137
pwm.cpp
Normal file
137
pwm.cpp
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
#include "pwm.h"
|
||||||
|
|
||||||
|
//16bit
|
||||||
|
|
||||||
|
Pwm16b::Pwm16b( volatile unsigned char *timerControlRegisterA, volatile unsigned char *timerControlRegisterB, volatile uint16_t *compareRegisterA, volatile uint16_t *compareRegisterB, volatile uint16_t *inputCaptureRegister, const uint8_t speed, const bool enableA, const bool enableB)
|
||||||
|
{
|
||||||
|
|
||||||
|
_timerControlRegisterA = timerControlRegisterA;
|
||||||
|
_compareRegisterA = compareRegisterA;
|
||||||
|
_compareRegisterB = compareRegisterB;
|
||||||
|
|
||||||
|
_enableA =enableA;
|
||||||
|
_enableB =enableB;
|
||||||
|
|
||||||
|
*_timerControlRegisterA = 0x00;
|
||||||
|
*timerControlRegisterB = 0x00;
|
||||||
|
*inputCaptureRegister = 0xFFFF;
|
||||||
|
*timerControlRegisterB |= (1<<WGM13) | (1<<WGM12);
|
||||||
|
*timerControlRegisterB |= 0b00000111 & speed;
|
||||||
|
*_timerControlRegisterA|= (1<<WGM11);
|
||||||
|
|
||||||
|
*_compareRegisterA = 0;
|
||||||
|
*_compareRegisterB = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Pwm16b::isOn()
|
||||||
|
{
|
||||||
|
return *_timerControlRegisterA != (1<<WGM11);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Pwm16b::off()
|
||||||
|
{
|
||||||
|
*_timerControlRegisterA = 0x00;
|
||||||
|
*_timerControlRegisterA |= (1<<WGM11);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Pwm16b::on()
|
||||||
|
{
|
||||||
|
off();
|
||||||
|
if(_enableA) *_timerControlRegisterA|= (1<<COM1A1);
|
||||||
|
if(_enableB) *_timerControlRegisterA|= (1<<COM1B1);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t Pwm16b::getValueA()
|
||||||
|
{
|
||||||
|
return *_compareRegisterA;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t Pwm16b::getValueB()
|
||||||
|
{
|
||||||
|
return *_compareRegisterB;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Pwm16b::setDutyA(const uint16_t duty)
|
||||||
|
{
|
||||||
|
*_compareRegisterA = duty;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Pwm16b::setDutyB(const uint16_t duty)
|
||||||
|
{
|
||||||
|
*_compareRegisterB = duty;
|
||||||
|
}
|
||||||
|
|
||||||
|
Pwm16b::~Pwm16b()
|
||||||
|
{
|
||||||
|
off();
|
||||||
|
}
|
||||||
|
|
||||||
|
//8bit
|
||||||
|
|
||||||
|
Pwm8b::Pwm8b( volatile unsigned char *timerControlRegisterA, volatile unsigned char *timerControlRegisterB, volatile unsigned char *compareRegisterA, volatile unsigned char *compareRegisterB, const uint8_t speed, const bool enableA, const bool enableB)
|
||||||
|
{
|
||||||
|
_timerControlRegisterA = timerControlRegisterA;
|
||||||
|
_compareRegisterA = compareRegisterA;
|
||||||
|
_compareRegisterB = compareRegisterB;
|
||||||
|
|
||||||
|
_enableA =enableA;
|
||||||
|
_enableB =enableB;
|
||||||
|
|
||||||
|
*_timerControlRegisterA = 0x00;
|
||||||
|
*timerControlRegisterB = 0x00;
|
||||||
|
|
||||||
|
//fast 8 bit PWM pwm A
|
||||||
|
if(_enableA) *_timerControlRegisterA|= (1<<COM0A1);
|
||||||
|
if(_enableB) *_timerControlRegisterA|= (1<<COM0B1);
|
||||||
|
|
||||||
|
*_timerControlRegisterA|= (1<<WGM01) | (1<<WGM00);
|
||||||
|
*timerControlRegisterB |= 0b00000111 & speed;
|
||||||
|
|
||||||
|
*_compareRegisterA = 0; //0% pwm to start0
|
||||||
|
*_compareRegisterB = 0; //0% pwm to start0
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Pwm8b::isOn()
|
||||||
|
{
|
||||||
|
return (*_timerControlRegisterA & 0x11111100) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Pwm8b::off()
|
||||||
|
{
|
||||||
|
*_timerControlRegisterA &= 0b00000011;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Pwm8b::on()
|
||||||
|
{
|
||||||
|
off();
|
||||||
|
if(_enableA) *_timerControlRegisterA|= (1<<COM0A1);
|
||||||
|
if(_enableB) *_timerControlRegisterA|= (1<<COM0B1);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t Pwm8b::getValueA()
|
||||||
|
{
|
||||||
|
return *_compareRegisterA;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t Pwm8b::getValueB()
|
||||||
|
{
|
||||||
|
return *_compareRegisterB;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Pwm8b::setDutyA(const uint8_t duty)
|
||||||
|
{
|
||||||
|
*_compareRegisterA = duty;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Pwm8b::setDutyB(const uint8_t duty)
|
||||||
|
{
|
||||||
|
*_compareRegisterB = duty;
|
||||||
|
}
|
||||||
|
|
||||||
|
Pwm8b::~Pwm8b()
|
||||||
|
{
|
||||||
|
off();
|
||||||
|
}
|
49
pwm.h
Normal file
49
pwm.h
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
#ifndef PWM_H
|
||||||
|
#define PWM_H
|
||||||
|
|
||||||
|
#include <avr/io.h>
|
||||||
|
|
||||||
|
class Pwm16b //TC1 pwm on PB1 & PB2
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
volatile unsigned char *_timerControlRegisterA; //TCCRxA
|
||||||
|
volatile uint16_t *_compareRegisterA; //OCRxA
|
||||||
|
volatile uint16_t *_compareRegisterB; //OCRxB
|
||||||
|
bool _enableA;
|
||||||
|
bool _enableB;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Pwm16b( volatile unsigned char *timerControlRegisterA, volatile unsigned char *timerControlRegisterB, volatile uint16_t *compareRegisterA, volatile uint16_t *compareRegisterB, volatile uint16_t *inputCaptureRegister, const uint8_t speed = 0b00000011, const bool enableA = true, const bool enableB = true);
|
||||||
|
~Pwm16b();
|
||||||
|
void setDutyA(const uint16_t duty);
|
||||||
|
void setDutyB(const uint16_t duty);
|
||||||
|
uint16_t getValueA();
|
||||||
|
uint16_t getValueB();
|
||||||
|
bool isOn();
|
||||||
|
void off();
|
||||||
|
void on();
|
||||||
|
};
|
||||||
|
|
||||||
|
class Pwm8b
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
volatile unsigned char *_timerControlRegisterA; //TCCRxA
|
||||||
|
volatile unsigned char *_compareRegisterA; //OCRxA
|
||||||
|
volatile unsigned char *_compareRegisterB; //OCRxB
|
||||||
|
|
||||||
|
bool _enableA;
|
||||||
|
bool _enableB;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Pwm8b( volatile unsigned char *timerControlRegisterA, volatile unsigned char *timerControlRegisterB, volatile unsigned char *compareRegisterA, volatile unsigned char *compareRegisterB, const uint8_t speed = 0b00000011, const bool enableA = true, const bool enableB = true);
|
||||||
|
~Pwm8b();
|
||||||
|
void setDutyA(const uint8_t duty);
|
||||||
|
void setDutyB(const uint8_t duty);
|
||||||
|
uint8_t getValueA();
|
||||||
|
uint8_t getValueB();
|
||||||
|
bool isOn();
|
||||||
|
void off();
|
||||||
|
void on();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
125
ringbuffer.h
Executable file
125
ringbuffer.h
Executable file
@ -0,0 +1,125 @@
|
|||||||
|
/*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, typename T = uint8_t >
|
||||||
|
class RingBuffer
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
|
||||||
|
volatile uint_fast16_t _headIndex = 0;
|
||||||
|
volatile uint_fast16_t _tailIndex = 0;
|
||||||
|
volatile bool _overrun = false;
|
||||||
|
volatile T _buffer[BUFFER_SIZE];
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
RingBuffer()
|
||||||
|
{
|
||||||
|
flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint_fast16_t remaining() const volatile
|
||||||
|
{
|
||||||
|
return (_headIndex-_tailIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint_fast16_t remainingCapacity() const volatile
|
||||||
|
{
|
||||||
|
return BUFFER_SIZE - (_headIndex-_tailIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isOverun() volatile
|
||||||
|
{
|
||||||
|
bool returnVal = _overrun;
|
||||||
|
_overrun = false;
|
||||||
|
return returnVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isEmpty() const volatile
|
||||||
|
{
|
||||||
|
return _tailIndex >= _headIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
T read() volatile
|
||||||
|
{
|
||||||
|
if(!isEmpty())
|
||||||
|
{
|
||||||
|
_tailIndex++;
|
||||||
|
return _buffer[(_tailIndex - 1) % BUFFER_SIZE];
|
||||||
|
}
|
||||||
|
else return '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int read( T* buffer, unsigned int length ) volatile
|
||||||
|
{
|
||||||
|
unsigned int i = 0;
|
||||||
|
for(; i < length && !isEmpty(); i++)
|
||||||
|
{
|
||||||
|
buffer[i] = read();
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
void write( T in ) volatile
|
||||||
|
{
|
||||||
|
if (_headIndex - BUFFER_SIZE > 0 && _tailIndex - BUFFER_SIZE > 0)
|
||||||
|
{
|
||||||
|
_headIndex -= BUFFER_SIZE;
|
||||||
|
_tailIndex -= BUFFER_SIZE;
|
||||||
|
}
|
||||||
|
_buffer[_headIndex % BUFFER_SIZE] = in;
|
||||||
|
_headIndex++;
|
||||||
|
if(remaining() > BUFFER_SIZE)
|
||||||
|
{
|
||||||
|
_overrun = true;
|
||||||
|
_tailIndex = _headIndex - BUFFER_SIZE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void write( T* buffer, const unsigned int length ) volatile
|
||||||
|
{
|
||||||
|
for(unsigned int i = 0; i < length; i++) write(buffer[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void flush(T flushCharacter = ' ') volatile
|
||||||
|
{
|
||||||
|
_headIndex = 0;
|
||||||
|
_tailIndex = 0;
|
||||||
|
for(int i = 0; i < BUFFER_SIZE; i++) _buffer[i] = flushCharacter;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int getString(T terminator, T* buffer, const unsigned int bufferLength) volatile
|
||||||
|
{
|
||||||
|
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(buffer, i);
|
||||||
|
buffer[i]='\0';
|
||||||
|
_tailIndex++;
|
||||||
|
}
|
||||||
|
else if(i == 0) _tailIndex++;
|
||||||
|
else i = 0;
|
||||||
|
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
};
|
21
sensor.h
Normal file
21
sensor.h
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
class Sensor
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
uint8_t id;
|
||||||
|
uint8_t type;
|
||||||
|
int16_t field;
|
||||||
|
|
||||||
|
Sensor(){}
|
||||||
|
Sensor(const uint8_t idIn, const uint8_t typeIn, const uint16_t fieldIn):
|
||||||
|
id(idIn), type(typeIn), field(fieldIn)
|
||||||
|
{}
|
||||||
|
|
||||||
|
bool operator==(const Sensor& in)
|
||||||
|
{
|
||||||
|
return id == in.id && type == in.type;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
128
serial.cpp
Normal file
128
serial.cpp
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
#include "serial.h"
|
||||||
|
#include "ringbuffer.h"
|
||||||
|
|
||||||
|
volatile RingBuffer<SERIAL_BUFFER_SIZE, volatile uint8_t> rxBuffer;
|
||||||
|
|
||||||
|
bool stopped = false;
|
||||||
|
|
||||||
|
ISR(USART_RX_vect) //I have seen worse interrupt sintax
|
||||||
|
{
|
||||||
|
rxBuffer.write(UDR0);
|
||||||
|
if(serialFlowControl && !stopped && rxBuffer.remainingCapacity() < 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
|
||||||
|
sei();
|
||||||
|
}
|
||||||
|
|
||||||
|
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.remainingCapacity() > 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, (uint8_t*)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 256
|
||||||
|
|
||||||
|
#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
|
||||||
|
|
43
shiftreg.h
Normal file
43
shiftreg.h
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <util/delay.h>
|
||||||
|
template <int BITS> class ShiftReg
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
static constexpr int BYTES = (BITS % 8 == 0) ? (BITS/8) : (BITS/8+1);
|
||||||
|
|
||||||
|
volatile unsigned char *_port;
|
||||||
|
const unsigned char _pinSer;
|
||||||
|
const unsigned char _pinSerClk;
|
||||||
|
const unsigned char _pinRClk;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
ShiftReg(volatile unsigned char* const port, const unsigned char pinSer, const unsigned char pinSerClk, const unsigned char pinRClk):
|
||||||
|
_port(port), _pinSer(pinSer), _pinSerClk(pinSerClk), _pinRClk(pinRClk)
|
||||||
|
{
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
void write(const unsigned char * const in)
|
||||||
|
{
|
||||||
|
*_port &= ~((1<<_pinSer) | (1<<_pinSerClk));
|
||||||
|
*_port |= 1<<_pinRClk;
|
||||||
|
for(unsigned char i = 0; i < BITS; ++i)
|
||||||
|
{
|
||||||
|
*_port &= ~(1 << _pinSerClk);
|
||||||
|
in[i/8] & (1<<(i%8)) ? (*_port |= (1 << _pinSer)) : (*_port &= ~(1 << _pinSer));
|
||||||
|
*_port |= (1 << _pinSerClk);
|
||||||
|
}
|
||||||
|
*_port &= ~(1<<_pinRClk);
|
||||||
|
}
|
||||||
|
void clear()
|
||||||
|
{
|
||||||
|
*_port &= ~((1<<_pinSer) | (1<<_pinSerClk));
|
||||||
|
*_port |= 1<<_pinRClk;
|
||||||
|
for(unsigned char i = 0; i < BITS; ++i)
|
||||||
|
{
|
||||||
|
*_port &= ~(1 << _pinSerClk);
|
||||||
|
*_port |= (1 << _pinSerClk);
|
||||||
|
}
|
||||||
|
*_port &= ~(1<<_pinRClk);
|
||||||
|
}
|
||||||
|
};
|
83
staticvector.h
Normal file
83
staticvector.h
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
template<typename T, size_t size> class SVector
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
size_t stored = 0;
|
||||||
|
|
||||||
|
T array[size];
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
T* data()
|
||||||
|
{
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
|
T& operator[](size_t i)
|
||||||
|
{
|
||||||
|
return array[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
T& at(size_t i)
|
||||||
|
{
|
||||||
|
return array[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
T& front()
|
||||||
|
{
|
||||||
|
return array[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
T& back()
|
||||||
|
{
|
||||||
|
return array[stored-1];
|
||||||
|
}
|
||||||
|
|
||||||
|
bool empty() const
|
||||||
|
{
|
||||||
|
return stored == 0 ? true : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t count() const
|
||||||
|
{
|
||||||
|
return stored;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr size_t maxSize() const
|
||||||
|
{
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t remainingCapacity() const
|
||||||
|
{
|
||||||
|
return size - stored;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool push_back(const T in)
|
||||||
|
{
|
||||||
|
if( remainingCapacity() != 0)
|
||||||
|
{
|
||||||
|
array[stored] = in;
|
||||||
|
++stored;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool erase(size_t position)
|
||||||
|
{
|
||||||
|
if(position > stored) return false;
|
||||||
|
array[position].~T();
|
||||||
|
--stored;
|
||||||
|
for( size_t i = position; i < stored; i++ ) memcpy(&array[i], &array[i+1], sizeof(T));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear()
|
||||||
|
{
|
||||||
|
for( size_t i = 0; i < stored; i++ ) array[i].~T();
|
||||||
|
stored = 0;
|
||||||
|
}
|
||||||
|
};
|
33
watchdog.h
Normal file
33
watchdog.h
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <avr/wdt.h>
|
||||||
|
|
||||||
|
#define wdt_set(value) \
|
||||||
|
__asm__ __volatile__ ( \
|
||||||
|
"in __tmp_reg__,__SREG__" "\n\t" \
|
||||||
|
"cli" "\n\t" \
|
||||||
|
"wdr" "\n\t" \
|
||||||
|
"sts %0,%1" "\n\t" \
|
||||||
|
"out __SREG__,__tmp_reg__" "\n\t" \
|
||||||
|
"sts %0,%2" \
|
||||||
|
: /* no outputs */ \
|
||||||
|
: "M" (_SFR_MEM_ADDR(_WD_CONTROL_REG)), \
|
||||||
|
"r" (_BV(_WD_CHANGE_BIT) | _BV(WDE)), \
|
||||||
|
"r" ((uint8_t) ((value & 0x08 ? _WD_PS3_MASK : 0x00) | \
|
||||||
|
_BV(WDIE) | (value & 0x07)) ) \
|
||||||
|
: "r0" \
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
#define wdt_off(x) \
|
||||||
|
__asm__ __volatile__ ( \
|
||||||
|
"in __tmp_reg__,__SREG__" "\n\t" \
|
||||||
|
"cli" "\n\t" \
|
||||||
|
"wdr" "\n\t" \
|
||||||
|
"sts %0,%1" "\n\t" \
|
||||||
|
"sts %0,%2" \
|
||||||
|
: /* no outputs */ \
|
||||||
|
: "M" (_SFR_MEM_ADDR(_WD_CONTROL_REG)), \
|
||||||
|
"r" (_BV(_WD_CHANGE_BIT) | _BV(WDE)), \
|
||||||
|
"r" ((uint8_t) (0x00)) \
|
||||||
|
: "r0" \
|
||||||
|
)
|
26
writepin.h
Normal file
26
writepin.h
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
#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 void setBit( volatile unsigned char *reg, const unsigned char bit, bool value )
|
||||||
|
{
|
||||||
|
writePin(reg, bit, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline void setDirection( volatile unsigned char *portDirReg, const unsigned char pin, bool makeOutput )
|
||||||
|
{
|
||||||
|
writePin(portDirReg, pin, makeOutput);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool readPin( volatile unsigned char *inPort, const unsigned char pin){ return (bool) (*inPort & (1 << pin));}
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
Reference in New Issue
Block a user