softmodem

This commit is contained in:
Nebel 2013-02-26 00:38:35 +09:00
parent e2a62bee98
commit 83508c313e
8 changed files with 814 additions and 327 deletions

View file

@ -0,0 +1,23 @@
K 25
svn:wc:ra_dav:version-url
V 33
/svn/!svn/ver/115/trunk/SoftModem
END
SoftModem.h
K 25
svn:wc:ra_dav:version-url
V 45
/svn/!svn/ver/115/trunk/SoftModem/SoftModem.h
END
keywords.txt
K 25
svn:wc:ra_dav:version-url
V 45
/svn/!svn/ver/39/trunk/SoftModem/keywords.txt
END
SoftModem.cpp
K 25
svn:wc:ra_dav:version-url
V 47
/svn/!svn/ver/117/trunk/SoftModem/SoftModem.cpp
END

View file

@ -0,0 +1,130 @@
10
dir
115
https://arms22.googlecode.com/svn/trunk/SoftModem
https://arms22.googlecode.com/svn
2012-09-15T06:54:54.354274Z
115
arms22@gmail.com
6844b672-8a06-11de-b664-3b115b7b7a9b
SoftModem.h
file
2012-10-08T18:17:20.000000Z
324ac64ba910e2bbb8ffc9a873735249
2012-09-15T06:54:54.354274Z
115
arms22@gmail.com
1672
keywords.txt
file
2012-09-02T06:36:09.000000Z
984fd1160834ff5b862ec7d60db3d34f
2010-05-06T10:56:24.509439Z
39
arms22
640
SoftModem.cpp
file
117
2012-10-10T13:40:55.000000Z
6ba1d1f635115b323154a60dc37cdb51
2012-11-12T13:40:36.532674Z
117
arms22@gmail.com
7548

View file

@ -0,0 +1,326 @@
#include "SoftModem.h"
#define TX_PIN (3)
#define RX_PIN1 (6) // AIN0
#define RX_PIN2 (7) // AIN1
SoftModem *SoftModem::activeObject = 0;
SoftModem::SoftModem() {
}
SoftModem::~SoftModem() {
end();
}
#if F_CPU == 16000000
#if SOFT_MODEM_BAUD_RATE <= 126
#define TIMER_CLOCK_SELECT (7)
#define MICROS_PER_TIMER_COUNT (clockCyclesToMicroseconds(1024))
#elif SOFT_MODEM_BAUD_RATE <= 315
#define TIMER_CLOCK_SELECT (6)
#define MICROS_PER_TIMER_COUNT (clockCyclesToMicroseconds(256))
#elif SOFT_MODEM_BAUD_RATE <= 630
#define TIMER_CLOCK_SELECT (5)
#define MICROS_PER_TIMER_COUNT (clockCyclesToMicroseconds(128))
#elif SOFT_MODEM_BAUD_RATE <= 1225
#define TIMER_CLOCK_SELECT (4)
#define MICROS_PER_TIMER_COUNT (clockCyclesToMicroseconds(64))
#else
#define TIMER_CLOCK_SELECT (3)
#define MICROS_PER_TIMER_COUNT (clockCyclesToMicroseconds(32))
#endif
#else
#if SOFT_MODEM_BAUD_RATE <= 126
#define TIMER_CLOCK_SELECT (6)
#define MICROS_PER_TIMER_COUNT (clockCyclesToMicroseconds(256))
#elif SOFT_MODEM_BAUD_RATE <= 315
#define TIMER_CLOCK_SELECT (5)
#define MICROS_PER_TIMER_COUNT (clockCyclesToMicroseconds(128))
#elif SOFT_MODEM_BAUD_RATE <= 630
#define TIMER_CLOCK_SELECT (4)
#define MICROS_PER_TIMER_COUNT (clockCyclesToMicroseconds(64))
#else
#define TIMER_CLOCK_SELECT (3)
#define MICROS_PER_TIMER_COUNT (clockCyclesToMicroseconds(32))
#endif
#endif
#define BIT_PERIOD (1000000/SOFT_MODEM_BAUD_RATE)
#define HIGH_FREQ_MICROS (1000000/SOFT_MODEM_HIGH_FREQ)
#define LOW_FREQ_MICROS (1000000/SOFT_MODEM_LOW_FREQ)
#define HIGH_FREQ_CNT (BIT_PERIOD/HIGH_FREQ_MICROS)
#define LOW_FREQ_CNT (BIT_PERIOD/LOW_FREQ_MICROS)
#define MAX_CARRIR_BITS (40000/BIT_PERIOD)
#define TCNT_BIT_PERIOD (BIT_PERIOD/MICROS_PER_TIMER_COUNT)
#define TCNT_HIGH_FREQ (HIGH_FREQ_MICROS/MICROS_PER_TIMER_COUNT)
#define TCNT_LOW_FREQ (LOW_FREQ_MICROS/MICROS_PER_TIMER_COUNT)
#define TCNT_HIGH_TH_L (TCNT_HIGH_FREQ * 0.90)
#define TCNT_HIGH_TH_H (TCNT_HIGH_FREQ * 1.15)
#define TCNT_LOW_TH_L (TCNT_LOW_FREQ * 0.85)
#define TCNT_LOW_TH_H (TCNT_LOW_FREQ * 1.10)
#if SOFT_MODEM_DEBUG_ENABLE
static volatile uint8_t *_portLEDReg;
static uint8_t _portLEDMask;
#endif
enum { START_BIT = 0, DATA_BIT = 8, STOP_BIT = 9, INACTIVE = 0xff };
void SoftModem::begin(void)
{
pinMode(RX_PIN1, INPUT);
digitalWrite(RX_PIN1, LOW);
pinMode(RX_PIN2, INPUT);
digitalWrite(RX_PIN2, LOW);
pinMode(TX_PIN, OUTPUT);
digitalWrite(TX_PIN, LOW);
_txPortReg = portOutputRegister(digitalPinToPort(TX_PIN));
_txPortMask = digitalPinToBitMask(TX_PIN);
#if SOFT_MODEM_DEBUG_ENABLE
_portLEDReg = portOutputRegister(digitalPinToPort(13));
_portLEDMask = digitalPinToBitMask(13);
pinMode(13, OUTPUT);
#endif
_recvStat = INACTIVE;
_recvBufferHead = _recvBufferTail = 0;
SoftModem::activeObject = this;
_lastTCNT = TCNT2;
_lastDiff = _lowCount = _highCount = 0;
TCCR2A = 0;
TCCR2B = TIMER_CLOCK_SELECT;
ACSR = _BV(ACIE) | _BV(ACIS1);
DIDR1 = _BV(AIN1D) | _BV(AIN0D);
}
void SoftModem::end(void)
{
ACSR &= ~(_BV(ACIE));
TIMSK2 &= ~(_BV(OCIE2A));
DIDR1 &= ~(_BV(AIN1D) | _BV(AIN0D));
SoftModem::activeObject = 0;
}
void SoftModem::demodulate(void)
{
uint8_t t = TCNT2;
uint8_t diff;
diff = t - _lastTCNT;
if(diff < 4)
return;
_lastTCNT = t;
if(diff > (uint8_t)(TCNT_LOW_TH_H))
return;
// 移動平均
_lastDiff = (diff >> 1) + (diff >> 2) + (_lastDiff >> 2);
if(_lastDiff >= (uint8_t)(TCNT_LOW_TH_L)){
_lowCount += _lastDiff;
if(_recvStat == INACTIVE){
// スタートビット検出
if(_lowCount >= (uint8_t)(TCNT_BIT_PERIOD * 0.5)){
_recvStat = START_BIT;
_highCount = 0;
_recvBits = 0;
OCR2A = t + (uint8_t)(TCNT_BIT_PERIOD) - _lowCount;
TIFR2 |= _BV(OCF2A);
TIMSK2 |= _BV(OCIE2A);
}
}
}
else if(_lastDiff <= (uint8_t)(TCNT_HIGH_TH_H)){
if(_recvStat == INACTIVE){
_lowCount = 0;
_highCount = 0;
}
else{
_highCount += _lastDiff;
}
}
}
// アナログコンパレータ割り込み
ISR(ANALOG_COMP_vect)
{
SoftModem::activeObject->demodulate();
}
void SoftModem::recv(void)
{
uint8_t high;
// ビット論理判定
if(_highCount > _lowCount){
_highCount = 0;
high = 0x80;
}
else{
_lowCount = 0;
high = 0x00;
}
// スタートビット受信
if(_recvStat == START_BIT){
if(!high){
_recvStat++;
}
else{
goto end_recv;
}
}
// データビット受信
else if(_recvStat <= DATA_BIT) {
_recvBits >>= 1;
_recvBits |= high;
_recvStat++;
}
// ストップビット受信
else if(_recvStat == STOP_BIT){
if(high){
// 受信バッファに格納
uint8_t new_tail = (_recvBufferTail + 1) & (SOFT_MODEM_RX_BUF_SIZE - 1);
if(new_tail != _recvBufferHead){
_recvBuffer[_recvBufferTail] = _recvBits;
_recvBufferTail = new_tail;
}
else{
;// オーバーランエラー
}
}
else{
;// フレミングエラー
}
goto end_recv;
}
else{
end_recv:
_recvStat = INACTIVE;
TIMSK2 &= ~_BV(OCIE2A);
}
}
// タイマー2比較一致割り込みA
ISR(TIMER2_COMPA_vect)
{
OCR2A += (uint8_t)TCNT_BIT_PERIOD;
SoftModem::activeObject->recv();
#if SOFT_MODEM_DEBUG_ENABLE
*_portLEDReg ^= _portLEDMask;
#endif
}
int SoftModem::available()
{
return (_recvBufferTail + SOFT_MODEM_RX_BUF_SIZE - _recvBufferHead) & (SOFT_MODEM_RX_BUF_SIZE - 1);
}
int SoftModem::read()
{
if(_recvBufferHead == _recvBufferTail)
return -1;
int d = _recvBuffer[_recvBufferHead];
_recvBufferHead = (_recvBufferHead + 1) & (SOFT_MODEM_RX_BUF_SIZE - 1);
return d;
}
int SoftModem::peek()
{
if(_recvBufferHead == _recvBufferTail)
return -1;
return _recvBuffer[_recvBufferHead];
}
void SoftModem::flush()
{
}
void SoftModem::modulate(uint8_t b)
{
uint8_t cnt,tcnt,tcnt2;
if(b){
cnt = (uint8_t)(HIGH_FREQ_CNT);
tcnt2 = (uint8_t)(TCNT_HIGH_FREQ / 2);
tcnt = (uint8_t)(TCNT_HIGH_FREQ) - tcnt2;
}else{
cnt = (uint8_t)(LOW_FREQ_CNT);
tcnt2 = (uint8_t)(TCNT_LOW_FREQ / 2);
tcnt = (uint8_t)(TCNT_LOW_FREQ) - tcnt2;
}
do {
cnt--;
{
OCR2B += tcnt;
TIFR2 |= _BV(OCF2B);
while(!(TIFR2 & _BV(OCF2B)));
}
*_txPortReg ^= _txPortMask;
{
OCR2B += tcnt2;
TIFR2 |= _BV(OCF2B);
while(!(TIFR2 & _BV(OCF2B)));
}
*_txPortReg ^= _txPortMask;
} while (cnt);
}
// Preamble bit before transmission
// 1 start bit (LOW)
// 8 data bits, LSB first
// 1 stop bit (HIGH)
// ...
// Postamble bit after transmission
size_t SoftModem::write(const uint8_t *buffer, size_t size)
{
// プリアンブルビット
uint8_t cnt = ((micros() - _lastWriteTime) / BIT_PERIOD) + 1;
if(cnt > MAX_CARRIR_BITS){
cnt = MAX_CARRIR_BITS;
}
for(uint8_t i = 0; i<cnt; i++){
modulate(HIGH);
}
size_t n = size;
while (size--) {
uint8_t data = *buffer++;
// スタート1ビット
modulate(LOW);
// データ8ビット
for(uint8_t mask = 1; mask; mask <<= 1){
if(data & mask){
modulate(HIGH);
}
else{
modulate(LOW);
}
}
// ストップ1ビット
modulate(HIGH);
}
// ポストアンブルビット
modulate(HIGH);
_lastWriteTime = micros();
return n;
}
size_t SoftModem::write(uint8_t data)
{
return write(&data, 1);
}

View file

@ -0,0 +1,65 @@
#ifndef SoftModem_h
#define SoftModem_h
#include <Arduino.h>
//#define SOFT_MODEM_BAUD_RATE (126)
//#define SOFT_MODEM_LOW_FREQ (882)
//#define SOFT_MODEM_HIGH_FREQ (1764)
//#define SOFT_MODEM_RX_BUF_SIZE (4)
//#define SOFT_MODEM_BAUD_RATE (315)
//#define SOFT_MODEM_LOW_FREQ (1575)
//#define SOFT_MODEM_HIGH_FREQ (3150)
//#define SOFT_MODEM_RX_BUF_SIZE (8)
//#define SOFT_MODEM_BAUD_RATE (630)
//#define SOFT_MODEM_LOW_FREQ (3150)
//#define SOFT_MODEM_HIGH_FREQ (6300)
//#define SOFT_MODEM_RX_BUF_SIZE (16)
#define SOFT_MODEM_BAUD_RATE (1225)
#define SOFT_MODEM_LOW_FREQ (4900)
#define SOFT_MODEM_HIGH_FREQ (7350)
#define SOFT_MODEM_RX_BUF_SIZE (32)
//#define SOFT_MODEM_BAUD_RATE (2450)
//#define SOFT_MODEM_LOW_FREQ (4900)
//#define SOFT_MODEM_HIGH_FREQ (7350)
//#define SOFT_MODEM_RX_BUF_SIZE (32)
#define SOFT_MODEM_DEBUG_ENABLE (0)
class SoftModem : public Stream
{
private:
volatile uint8_t *_txPortReg;
uint8_t _txPortMask;
uint8_t _lastTCNT;
uint8_t _lastDiff;
uint8_t _recvStat;
uint8_t _recvBits;
uint8_t _recvBufferHead;
uint8_t _recvBufferTail;
uint8_t _recvBuffer[SOFT_MODEM_RX_BUF_SIZE];
uint8_t _lowCount;
uint8_t _highCount;
unsigned long _lastWriteTime;
void modulate(uint8_t b);
public:
SoftModem();
~SoftModem();
void begin(void);
void end(void);
virtual int available();
virtual int read();
virtual void flush();
virtual int peek();
virtual size_t write(const uint8_t *buffer, size_t size);
virtual size_t write(uint8_t data);
void demodulate(void);
void recv(void);
static SoftModem *activeObject;
};
#endif

View file

@ -0,0 +1,26 @@
#######################################
# Syntax Coloring Map For SoftModem
#######################################
#######################################
# Datatypes (KEYWORD1)
#######################################
SoftModem KEYWORD1
#######################################
# Methods and Functions (KEYWORD2)
#######################################
begin KEYWORD2
end KEYWORD2
available KEYWORD2
read KEYWORD2
write KEYWORD2
#######################################
# Instances (KEYWORD2)
#######################################
#######################################
# Constants (LITERAL1)
#######################################

View file

@ -1,12 +1,8 @@
#include <WProgram.h>
#include <WConstants.h>
#include <avr/interrupt.h>
#include <pins_arduino.h>
#include "SoftModem.h"
#define SOFT_MODEM_TX_PIN (3)
#define SOFT_MODEM_RX_PIN1 (6) // AIN0
#define SOFT_MODEM_RX_PIN2 (7) // AIN1
#define TX_PIN (3)
#define RX_PIN1 (6) // AIN0
#define RX_PIN2 (7) // AIN1
SoftModem *SoftModem::activeObject = 0;
@ -19,135 +15,112 @@ SoftModem::~SoftModem() {
#if F_CPU == 16000000
#if SOFT_MODEM_BAUD_RATE <= 126
#define TIMER_CLOCK_SELECT (7)
#define MICROS_PER_TIMER_COUNT (clockCyclesToMicroseconds(1024))
#define TIMER_CLOCK_SELECT (7)
#define MICROS_PER_TIMER_COUNT (clockCyclesToMicroseconds(1024))
#elif SOFT_MODEM_BAUD_RATE <= 315
#define TIMER_CLOCK_SELECT (6)
#define MICROS_PER_TIMER_COUNT (clockCyclesToMicroseconds(256))
#define TIMER_CLOCK_SELECT (6)
#define MICROS_PER_TIMER_COUNT (clockCyclesToMicroseconds(256))
#elif SOFT_MODEM_BAUD_RATE <= 630
#define TIMER_CLOCK_SELECT (5)
#define MICROS_PER_TIMER_COUNT (clockCyclesToMicroseconds(128))
#define TIMER_CLOCK_SELECT (5)
#define MICROS_PER_TIMER_COUNT (clockCyclesToMicroseconds(128))
#elif SOFT_MODEM_BAUD_RATE <= 1225
#define TIMER_CLOCK_SELECT (4)
#define MICROS_PER_TIMER_COUNT (clockCyclesToMicroseconds(64))
#define TIMER_CLOCK_SELECT (4)
#define MICROS_PER_TIMER_COUNT (clockCyclesToMicroseconds(64))
#else
#define TIMER_CLOCK_SELECT (3)
#define MICROS_PER_TIMER_COUNT (clockCyclesToMicroseconds(32))
#define TIMER_CLOCK_SELECT (3)
#define MICROS_PER_TIMER_COUNT (clockCyclesToMicroseconds(32))
#endif
#else
#if SOFT_MODEM_BAUD_RATE <= 126
#define TIMER_CLOCK_SELECT (6)
#define MICROS_PER_TIMER_COUNT (clockCyclesToMicroseconds(256))
#define TIMER_CLOCK_SELECT (6)
#define MICROS_PER_TIMER_COUNT (clockCyclesToMicroseconds(256))
#elif SOFT_MODEM_BAUD_RATE <= 315
#define TIMER_CLOCK_SELECT (5)
#define MICROS_PER_TIMER_COUNT (clockCyclesToMicroseconds(128))
#define TIMER_CLOCK_SELECT (5)
#define MICROS_PER_TIMER_COUNT (clockCyclesToMicroseconds(128))
#elif SOFT_MODEM_BAUD_RATE <= 630
#define TIMER_CLOCK_SELECT (4)
#define MICROS_PER_TIMER_COUNT (clockCyclesToMicroseconds(64))
#define TIMER_CLOCK_SELECT (4)
#define MICROS_PER_TIMER_COUNT (clockCyclesToMicroseconds(64))
#else
#define TIMER_CLOCK_SELECT (3)
#define MICROS_PER_TIMER_COUNT (clockCyclesToMicroseconds(32))
#define TIMER_CLOCK_SELECT (3)
#define MICROS_PER_TIMER_COUNT (clockCyclesToMicroseconds(32))
#endif
#endif
#define SOFT_MODEM_BIT_PERIOD (1000000/SOFT_MODEM_BAUD_RATE)
#define SOFT_MODEM_HIGH_USEC (1000000/SOFT_MODEM_HIGH_FREQ)
#define SOFT_MODEM_LOW_USEC (1000000/SOFT_MODEM_LOW_FREQ)
#define BIT_PERIOD (1000000/SOFT_MODEM_BAUD_RATE)
#define HIGH_FREQ_MICROS (1000000/SOFT_MODEM_HIGH_FREQ)
#define LOW_FREQ_MICROS (1000000/SOFT_MODEM_LOW_FREQ)
#define SOFT_MODEM_HIGH_CNT (SOFT_MODEM_BIT_PERIOD/SOFT_MODEM_HIGH_USEC)
#define SOFT_MODEM_LOW_CNT (SOFT_MODEM_BIT_PERIOD/SOFT_MODEM_LOW_USEC)
#define HIGH_FREQ_CNT (BIT_PERIOD/HIGH_FREQ_MICROS)
#define LOW_FREQ_CNT (BIT_PERIOD/LOW_FREQ_MICROS)
#define SOFT_MODEM_HIGH_ADJ (SOFT_MODEM_BIT_PERIOD%SOFT_MODEM_HIGH_USEC)
#define SOFT_MODEM_LOW_ADJ (SOFT_MODEM_BIT_PERIOD%SOFT_MODEM_LOW_USEC)
#define MAX_CARRIR_BITS (40000/BIT_PERIOD)
#define SOFT_MODEM_CARRIR_CNT (20000000/SOFT_MODEM_BIT_PERIOD)
#define TCNT_BIT_PERIOD (BIT_PERIOD/MICROS_PER_TIMER_COUNT)
#define TCNT_HIGH_FREQ (HIGH_FREQ_MICROS/MICROS_PER_TIMER_COUNT)
#define TCNT_LOW_FREQ (LOW_FREQ_MICROS/MICROS_PER_TIMER_COUNT)
#define TCNT_BIT_PERIOD (SOFT_MODEM_BIT_PERIOD/MICROS_PER_TIMER_COUNT)
#define TCNT_HIGH_FREQ (SOFT_MODEM_HIGH_USEC/MICROS_PER_TIMER_COUNT)
#define TCNT_LOW_FREQ (SOFT_MODEM_LOW_USEC/MICROS_PER_TIMER_COUNT)
#define TCNT_HIGH_TH_L (TCNT_HIGH_FREQ * 0.90)
#define TCNT_HIGH_TH_H (TCNT_HIGH_FREQ * 1.15)
#define TCNT_LOW_TH_L (TCNT_LOW_FREQ * 0.85)
#define TCNT_LOW_TH_H (TCNT_LOW_FREQ * 1.10)
#define TCNT_HIGH_TH_L (TCNT_HIGH_FREQ * 0.80)
#define TCNT_HIGH_TH_H (TCNT_HIGH_FREQ * 1.15)
#define TCNT_LOW_TH_L (TCNT_LOW_FREQ * 0.85)
#define TCNT_LOW_TH_H (TCNT_LOW_FREQ * 1.20)
#if SOFT_MODEM_DEBUG
static volatile uint8_t *portLEDReg;
static uint8_t portLEDMask;
#if SOFT_MODEM_DEBUG_ENABLE
static volatile uint8_t *_portLEDReg;
static uint8_t _portLEDMask;
#endif
enum { START_BIT = 0, DATA_BIT = 8, STOP_BIT = 9, INACTIVE = 0xff };
void SoftModem::begin(void)
{
pinMode(SOFT_MODEM_RX_PIN1, INPUT);
digitalWrite(SOFT_MODEM_RX_PIN1, LOW);
pinMode(SOFT_MODEM_RX_PIN2, INPUT);
digitalWrite(SOFT_MODEM_RX_PIN2, LOW);
pinMode(SOFT_MODEM_TX_PIN, OUTPUT);
digitalWrite(SOFT_MODEM_TX_PIN, LOW);
_txPortReg = portOutputRegister(digitalPinToPort(SOFT_MODEM_TX_PIN));
_txPortMask = digitalPinToBitMask(SOFT_MODEM_TX_PIN);
#if SOFT_MODEM_DEBUG
portLEDReg = portOutputRegister(digitalPinToPort(13));
portLEDMask = digitalPinToBitMask(13);
_errs = 0;
_ints = 0;
pinMode(RX_PIN1, INPUT);
digitalWrite(RX_PIN1, LOW);
pinMode(RX_PIN2, INPUT);
digitalWrite(RX_PIN2, LOW);
pinMode(TX_PIN, OUTPUT);
digitalWrite(TX_PIN, LOW);
_txPortReg = portOutputRegister(digitalPinToPort(TX_PIN));
_txPortMask = digitalPinToBitMask(TX_PIN);
#if SOFT_MODEM_DEBUG_ENABLE
_portLEDReg = portOutputRegister(digitalPinToPort(13));
_portLEDMask = digitalPinToBitMask(13);
pinMode(13, OUTPUT);
#endif
_recvStat = 0xff;
_recvStat = INACTIVE;
_recvBufferHead = _recvBufferTail = 0;
SoftModem::activeObject = this;
_lastTCNT = TCNT2;
_lastDiff = _lowCount = _highCount = 0;
TCCR2A = 0;
TCCR2B = TIMER_CLOCK_SELECT;
ACSR = _BV(ACIE) | _BV(ACIS1);
DIDR1 = _BV(AIN1D) | _BV(AIN0D);
}
void SoftModem::end(void)
{
ACSR &= ~(_BV(ACIE));
TIMSK2 &= ~(_BV(OCIE2A));
DIDR1 &= ~(_BV(AIN1D) | _BV(AIN0D));
SoftModem::activeObject = 0;
}
enum {
FSK_START_BIT = 0,
FSK_D0_BIT,
FSK_D1_BIT,
FSK_D2_BIT,
FSK_D3_BIT,
FSK_D4_BIT,
FSK_D5_BIT,
FSK_D6_BIT,
FSK_D7_BIT,
FSK_STOP_BIT
};
void SoftModem::demodulate(void)
{
uint8_t t = TCNT2;
uint8_t diff;
if(TIFR2 & _BV(TOV2)){
TIFR2 |= _BV(TOV2);
diff = (255 - _lastTCNT) + t + 1;
}
else{
diff = t - _lastTCNT;
}
diff = t - _lastTCNT;
#if SOFT_MODEM_DEBUG
_ints++;
#endif
if(diff < (uint8_t)(TCNT_HIGH_TH_L)) // Noise?
if(diff < 4)
return;
_lastTCNT = t;
@ -155,122 +128,138 @@ void SoftModem::demodulate(void)
if(diff > (uint8_t)(TCNT_LOW_TH_H))
return;
// 移動平均
_lastDiff = (diff >> 1) + (diff >> 2) + (_lastDiff >> 2);
if(_lastDiff >= (uint8_t)(TCNT_LOW_TH_L)){
_lowCount += _lastDiff;
if((_recvStat == 0xff) && (_lowCount >= (uint8_t)(TCNT_BIT_PERIOD * 0.5))){ // maybe Start-Bit
_recvStat = FSK_START_BIT;
_highCount = 0;
_recvBits = 0;
OCR2A = t + (uint8_t)(TCNT_BIT_PERIOD) - _lowCount; // 1 bit period after detected
TIFR2 |= _BV(OCF2A);
TIMSK2 |= _BV(OCIE2A);
if(_recvStat == INACTIVE){
// スタートビット検出
if(_lowCount >= (uint8_t)(TCNT_BIT_PERIOD * 0.5)){
_recvStat = START_BIT;
_highCount = 0;
_recvBits = 0;
OCR2A = t + (uint8_t)(TCNT_BIT_PERIOD) - _lowCount;
TIFR2 |= _BV(OCF2A);
TIMSK2 |= _BV(OCIE2A);
}
}
}
else if(_lastDiff <= (uint8_t)(TCNT_HIGH_TH_H)){
_highCount += _lastDiff;
if((_recvStat == 0xff) && (_highCount >= (uint8_t)(TCNT_BIT_PERIOD))){
_lowCount = _highCount = 0;
if(_recvStat == INACTIVE){
_lowCount = 0;
_highCount = 0;
}
else{
_highCount += _lastDiff;
}
}
else{
#if SOFT_MODEM_DEBUG
_errs++;
#endif
}
}
// アナログコンパレータ割り込み
ISR(ANALOG_COMP_vect)
{
SoftModem *act = SoftModem::activeObject;
act->demodulate();
SoftModem::activeObject->demodulate();
}
void SoftModem::recv(void)
{
uint8_t high;
// ビット論理判定
if(_highCount > _lowCount){
if(_highCount >= (uint8_t)TCNT_BIT_PERIOD)
_highCount -= (uint8_t)TCNT_BIT_PERIOD;
else
_highCount = 0;
_highCount = 0;
high = 0x80;
}
else{
if(_lowCount >= (uint8_t)TCNT_BIT_PERIOD)
_lowCount -= (uint8_t)TCNT_BIT_PERIOD;
else
_lowCount = 0;
_lowCount = 0;
high = 0x00;
}
if(_recvStat == FSK_START_BIT){ // Start bit
// スタートビット受信
if(_recvStat == START_BIT){
if(!high){
_recvStat++;
}else{
}
else{
goto end_recv;
}
}
else if(_recvStat <= FSK_D7_BIT) { // Data bits
// データビット受信
else if(_recvStat <= DATA_BIT) {
_recvBits >>= 1;
_recvBits |= high;
_recvStat++;
}
else if(_recvStat == FSK_STOP_BIT){ // Stop bit
uint8_t new_tail = (_recvBufferTail + 1) & (SOFT_MODEM_MAX_RX_BUFF - 1);
if(new_tail != _recvBufferHead){
_recvBuffer[_recvBufferTail] = _recvBits;
_recvBufferTail = new_tail;
// ストップビット受信
else if(_recvStat == STOP_BIT){
if(high){
// 受信バッファに格納
uint8_t new_tail = (_recvBufferTail + 1) & (SOFT_MODEM_RX_BUF_SIZE - 1);
if(new_tail != _recvBufferHead){
_recvBuffer[_recvBufferTail] = _recvBits;
_recvBufferTail = new_tail;
}
else{
;// オーバーランエラー
}
}
else{
;// フレミングエラー
}
goto end_recv;
}
else{
end_recv:
_recvStat = 0xff;
_recvStat = INACTIVE;
TIMSK2 &= ~_BV(OCIE2A);
#if SOFT_MODEM_DEBUG
errs = _errs;
_errs = 0;
ints = _ints;
_ints = 0;
#endif
}
}
// タイマー2比較一致割り込みA
ISR(TIMER2_COMPA_vect)
{
OCR2A += (uint8_t)TCNT_BIT_PERIOD;
SoftModem *act = SoftModem::activeObject;
act->recv();
#if SOFT_MODEM_DEBUG
*portLEDReg ^= portLEDMask;
#endif
SoftModem::activeObject->recv();
#if SOFT_MODEM_DEBUG_ENABLE
*_portLEDReg ^= _portLEDMask;
#endif
}
uint8_t SoftModem::available(void)
int SoftModem::available()
{
return (_recvBufferTail + SOFT_MODEM_MAX_RX_BUFF - _recvBufferHead) & (SOFT_MODEM_MAX_RX_BUFF - 1);
return (_recvBufferTail + SOFT_MODEM_RX_BUF_SIZE - _recvBufferHead) & (SOFT_MODEM_RX_BUF_SIZE - 1);
}
int SoftModem::read(void)
int SoftModem::read()
{
if(_recvBufferHead == _recvBufferTail)
return -1;
int d = _recvBuffer[_recvBufferHead];
_recvBufferHead = (_recvBufferHead + 1) & (SOFT_MODEM_MAX_RX_BUFF - 1);
_recvBufferHead = (_recvBufferHead + 1) & (SOFT_MODEM_RX_BUF_SIZE - 1);
return d;
}
int SoftModem::peek()
{
if(_recvBufferHead == _recvBufferTail)
return -1;
return _recvBuffer[_recvBufferHead];
}
void SoftModem::flush()
{
}
void SoftModem::modulate(uint8_t b)
{
uint8_t cnt,tcnt,tcnt2,adj;
uint8_t cnt,tcnt,tcnt2;
if(b){
cnt = (uint8_t)(SOFT_MODEM_HIGH_CNT);
cnt = (uint8_t)(HIGH_FREQ_CNT);
tcnt2 = (uint8_t)(TCNT_HIGH_FREQ / 2);
tcnt = (uint8_t)(TCNT_HIGH_FREQ) - tcnt2;
}else{
cnt = (uint8_t)(SOFT_MODEM_LOW_CNT);
cnt = (uint8_t)(LOW_FREQ_CNT);
tcnt2 = (uint8_t)(TCNT_LOW_FREQ / 2);
tcnt = (uint8_t)(TCNT_LOW_FREQ) - tcnt2;
}
@ -291,149 +280,47 @@ void SoftModem::modulate(uint8_t b)
} while (cnt);
}
void SoftModem::write(uint8_t data)
// Preamble bit before transmission
// 1 start bit (LOW)
// 8 data bits, LSB first
// 1 stop bit (HIGH)
// ...
// Postamble bit after transmission
size_t SoftModem::write(const uint8_t *buffer, size_t size)
{
static unsigned long lastTransmissionTime = 0;
if((micros() - lastTransmissionTime) > (uint16_t)(SOFT_MODEM_LOW_USEC*2)){
for(uint8_t i = 0; i<(uint8_t)SOFT_MODEM_CARRIR_CNT; i++){
modulate(HIGH);
}
// プリアンブルビット
uint8_t cnt = ((micros() - _lastWriteTime) / BIT_PERIOD) + 1;
if(cnt > MAX_CARRIR_BITS){
cnt = MAX_CARRIR_BITS;
}
modulate(LOW); // Start Bit
for(uint8_t mask = 1; mask; mask <<= 1){ // Data Bits
if(data & mask){
modulate(HIGH);
}
else{
modulate(LOW);
}
for(uint8_t i = 0; i<cnt; i++){
modulate(HIGH);
}
modulate(HIGH); // Stop Bit
modulate(HIGH); // Push Bit
lastTransmissionTime = micros();
size_t n = size;
while (size--) {
uint8_t data = *buffer++;
// スタート1ビット
modulate(LOW);
// データ8ビット
for(uint8_t mask = 1; mask; mask <<= 1){
if(data & mask){
modulate(HIGH);
}
else{
modulate(LOW);
}
}
// ストップ1ビット
modulate(HIGH);
}
// ポストアンブルビット
modulate(HIGH);
_lastWriteTime = micros();
return n;
}
#if SOFT_MODEM_DEBUG
#include <HardwareSerial.h>
void SoftModem::handleAnalogComp(bool high)
size_t SoftModem::write(uint8_t data)
{
int cnt = (high ? SOFT_MODEM_HIGH_CNT : SOFT_MODEM_LOW_CNT);
int usec = (high ? SOFT_MODEM_HIGH_USEC : SOFT_MODEM_LOW_USEC);
int adj = (high ? SOFT_MODEM_HIGH_ADJ : SOFT_MODEM_LOW_ADJ);
for(int i=0;i<cnt;i++){
unsigned long end = micros() + usec;
demodulate();
while(micros() < end);
}
if(adj)
delayMicroseconds(adj);
return write(&data, 1);
}
void SoftModem::demodulateTest(void)
{
Serial.print("bit period = ");
Serial.println(SOFT_MODEM_BIT_PERIOD);
Serial.print("low usec = ");
Serial.println(SOFT_MODEM_LOW_USEC);
Serial.print("high usec = ");
Serial.println(SOFT_MODEM_HIGH_USEC);
Serial.print("low cnt = ");
Serial.println(SOFT_MODEM_LOW_CNT);
Serial.print("high cnt = ");
Serial.println(SOFT_MODEM_HIGH_CNT);
Serial.print("low adj = ");
Serial.println(SOFT_MODEM_LOW_ADJ);
Serial.print("high adj = ");
Serial.println(SOFT_MODEM_HIGH_ADJ);
Serial.print("TMC micros = ");
Serial.println(MICROS_PER_TIMER_COUNT);
Serial.println("low freq TMC > ");
Serial.println(TCNT_LOW_FREQ,DEC);
Serial.println(TCNT_LOW_TH_L,DEC);
Serial.println(TCNT_LOW_TH_H,DEC);
Serial.println("high freq TMC > ");
Serial.println(TCNT_HIGH_FREQ,DEC);
Serial.println(TCNT_HIGH_TH_L,DEC);
Serial.println(TCNT_HIGH_TH_H,DEC);
Serial.print("bit period TMC = ");
Serial.println(TCNT_BIT_PERIOD,DEC);
begin();
delay(200);
handleAnalogComp(0);//start bit
handleAnalogComp(1);
handleAnalogComp(0);
handleAnalogComp(1);
handleAnalogComp(0);
handleAnalogComp(0);
handleAnalogComp(1);
handleAnalogComp(0);
handleAnalogComp(1);
handleAnalogComp(1);//parity bit
handleAnalogComp(1);//stop bit
delay(300);
handleAnalogComp(0);//start bit
handleAnalogComp(1);
handleAnalogComp(1);
handleAnalogComp(1);
handleAnalogComp(0);
handleAnalogComp(1);
handleAnalogComp(1);
handleAnalogComp(1);
handleAnalogComp(0);
handleAnalogComp(1);//parity bit
handleAnalogComp(1);//stop bit
delay(300);
handleAnalogComp(0);//start bit
handleAnalogComp(0);
handleAnalogComp(1);
handleAnalogComp(1);
handleAnalogComp(1);
handleAnalogComp(0);
handleAnalogComp(1);
handleAnalogComp(1);
handleAnalogComp(1);
handleAnalogComp(1);//parity bit
handleAnalogComp(1);//stop bit
delay(300);
Serial.println("--");
Serial.println(_recvStat,HEX);
Serial.println(_lastTCNT,HEX);
Serial.println(_recvBits,HEX);
while(available()){
Serial.print("data=");
Serial.println(read(),HEX);
}
end();
}
#endif

View file

@ -1,53 +1,36 @@
#ifndef SoftModem_h
#define SoftModem_h
#include <Print.h>
#include <inttypes.h>
#include <Arduino.h>
//#define SOFT_MODEM_BAUD_RATE (126)
//#define SOFT_MODEM_LOW_FREQ (882)
//#define SOFT_MODEM_HIGH_FREQ (1764)
//#define SOFT_MODEM_MAX_RX_BUFF (4)
//#define SOFT_MODEM_RX_BUF_SIZE (4)
//#define SOFT_MODEM_BAUD_RATE (100)
//#define SOFT_MODEM_LOW_FREQ (800)
//#define SOFT_MODEM_HIGH_FREQ (1600)
//#define SOFT_MODEM_MAX_RX_BUFF (4)
//#define SOFT_MODEM_BAUD_RATE (315)
//#define SOFT_MODEM_LOW_FREQ (1575)
//#define SOFT_MODEM_HIGH_FREQ (3150)
//#define SOFT_MODEM_RX_BUF_SIZE (8)
// #define SOFT_MODEM_BAUD_RATE (315)
// #define SOFT_MODEM_LOW_FREQ (1575)
// #define SOFT_MODEM_HIGH_FREQ (3150)
// #define SOFT_MODEM_MAX_RX_BUFF (8)
// #define SOFT_MODEM_BAUD_RATE (630)
// #define SOFT_MODEM_LOW_FREQ (3150)
// #define SOFT_MODEM_HIGH_FREQ (6300)
// #define SOFT_MODEM_MAX_RX_BUFF (16)
//#define SOFT_MODEM_BAUD_RATE (600)
//#define SOFT_MODEM_LOW_FREQ (2666)
//#define SOFT_MODEM_HIGH_FREQ (4000)
//#define SOFT_MODEM_MAX_RX_BUFF (16)
//#define SOFT_MODEM_BAUD_RATE (630)
//#define SOFT_MODEM_LOW_FREQ (3150)
//#define SOFT_MODEM_HIGH_FREQ (6300)
//#define SOFT_MODEM_RX_BUF_SIZE (16)
#define SOFT_MODEM_BAUD_RATE (1225)
#define SOFT_MODEM_LOW_FREQ (4900)
#define SOFT_MODEM_HIGH_FREQ (7350)
#define SOFT_MODEM_MAX_RX_BUFF (32)
#define SOFT_MODEM_RX_BUF_SIZE (32)
//#define SOFT_MODEM_BAUD_RATE (2450)
//#define SOFT_MODEM_LOW_FREQ (7350)
//#define SOFT_MODEM_HIGH_FREQ (14700)
//#define SOFT_MODEM_MAX_RX_BUFF (32)
//#define SOFT_MODEM_LOW_FREQ (4900)
//#define SOFT_MODEM_HIGH_FREQ (7350)
//#define SOFT_MODEM_RX_BUF_SIZE (32)
// Brief carrier tone before each transmission
// 1 start bit (LOW)
// 8 data bits, LSB first
// 1 stop bit (HIGH)
// 1 push bit (HIGH)
#define SOFT_MODEM_DEBUG_ENABLE (0)
#define SOFT_MODEM_DEBUG (0)
class SoftModem : public Print
class SoftModem : public Stream
{
private:
volatile uint8_t *_txPortReg;
@ -58,29 +41,25 @@ private:
uint8_t _recvBits;
uint8_t _recvBufferHead;
uint8_t _recvBufferTail;
uint8_t _recvBuffer[SOFT_MODEM_MAX_RX_BUFF];
uint8_t _recvBuffer[SOFT_MODEM_RX_BUF_SIZE];
uint8_t _lowCount;
uint8_t _highCount;
unsigned long _lastWriteTime;
void modulate(uint8_t b);
public:
SoftModem();
~SoftModem();
void begin(void);
void end(void);
uint8_t available(void);
int read(void);
void write(uint8_t data);
virtual int available();
virtual int read();
virtual void flush();
virtual int peek();
virtual size_t write(const uint8_t *buffer, size_t size);
virtual size_t write(uint8_t data);
void demodulate(void);
void recv(void);
static SoftModem *activeObject;
#if SOFT_MODEM_DEBUG
void handleAnalogComp(bool high);
void demodulateTest(void);
uint8_t _errs;
uint16_t _ints;
uint8_t errs;
uint16_t ints;
#endif
};
#endif

View file

@ -0,0 +1,51 @@
/*
Arduinoとは次のように接続しますArduinoの端子
* FSKOUTD3
* GNDGND
* VCCVCC
* FSKIND6
* AIN1D7
調
Arduinoの電源電圧に合わせて調整しますAIN1の電圧をテスターで計り(VCC / 2) + 300mVになるよう調節します
* 5V電源の場合2.7V
* 3.3V電源の場合1.95V
- http://code.google.com/p/arms22/wiki/SoftModemBreakoutBoard
*/
#include <SoftModem.h>
#include <ctype.h>
SoftModem modem;
void setup()
{
Serial.begin(57600);
delay(1000);
modem.begin();
}
void loop()
{
while(modem.available()){
char c = modem.read();
if(isprint(c)){
Serial.print(c);
}
else{
Serial.print("\\x");
Serial.print((uint8_t)c,HEX);
}
}
if(Serial.available()){
modem.write(0xff);
while(Serial.available()){
char c = Serial.read();
modem.write(c);
}
}
}