Rev 305 | Rev 307 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download
//----------------------------------------------------------------------------------
// Prevodnik RS232 <--> RS485
// pri startbitu na RS232 zapne okamzite vysilac pokud nejsou detekovana data z RS485.
//----------------------------------------------------------------------------------
//
//Algoritmus:
// Princip je zalozen na mereni nejkratsiho casoveho useku v osmi vzorcich, delka vzorku
// se odviji od velikosti prave nejmensiho zmereneho vzorku.
// delka vzorku se meri pomoci 8mi bitoveho casovace a interruptu od zmeny vstupu. casovac je osetren
// proti pretekani (pocet preteceni se uklada, do promenne s ktere se zpetne vypocita 16bitove cislo,
// casovac se tedy virtualne chova jako 16ti bitovy.)
//
// Tento zpusob detekce neni imuni proti nahodnym chybovim spickam vzniklych v dusledku ruseni.
// Proto je nutene napajeni kvalitne stbilizovat, pouzivat blokovaci kondenzatory a
// zabezpecit, aby nedochazelo ke zvedani zeme.
/////////////////////////////////////////////////////////////////////////////////////
//
//TODO:
// Optimalizovat kod, (hlavne najit casove vyhodnejsi umisteni pro nastavovani defaultnich hodnot promennych)
// Bylo bydobre zavest uspavani pred prijetim bajtu.
// Vykouset program na ATtiny13
// Program neni vyzkousen pri extremne nizkych rychlostech, kdy by teoreticky
// mohlo dochazet k preteceni promenne cas.
// Neni vyzkousen break, byly testovany pouze ASCII znaky vysilane pres terminal z klavesnice.
//////////////////////////////////////////////////////////////////////////////////////
//
#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdlib.h>
#include <ctype.h>
#include <avr/eeprom.h>
#include <avr/pgmspace.h>
#define POVOLOVAK_LOW PORTB &= ~(1<<PB3) // nastaveni nuly na vystup, krery zapina povoleni vysilani RS485
#define POVOLOVAK_HIGH PORTB |= (1<<PB3) // nastaveni jednicky na tentyz vystup
#define DATA (PIND & (1<<PD3)) // nastaveni vstupu, na kterem se budou detekovat data, musi byt stejny jako vstup pouziteho interruptu
volatile unsigned int preteceni; // promenna na ukladani poctu preteceni casovace
volatile unsigned int bit; // promena pro pocitani bitu v bajtu
volatile unsigned int bitdelay; // obsahuje aktualni zmereny cas delky bitu
volatile unsigned int cas; // urcuje nejkratsi nalezeny cas delky bitu
ISR(TIMER0_OVF_vect) // interrupt od preteceni casovace
{
preteceni++; // kdyz pretece, poznamenej to.
}
ISR(INT1_vect) // interrupt od zmeny vstupu na datech
{
if ((bitdelay=TCNT0+preteceni*0x0100) < cas) cas = bitdelay; // provnani jestli zrovna zmereny cas je kratsi nez nejmensi znamy cas
TCNT0 = 0; // zacni znova merit cas zacatku stopbitu
preteceni=0; // vynuluj vsechny casove promenne
bit++; // posun pocitadlo bitu o jednicku
}
// ------------------------------------------------------------------
// Main
// ------------------------------------------------------------------
int main(void)
{
int stopbit;
// DDRD |= (1<<DDD5); // povoleni vystupu pro blikani ledkou (mozno odebrat)
DDRB |= (1<<DDB3); // povoleni vystupu na povolovak
TIMSK |= (1 << TOIE0); // Enable timer overflow interrupt
MCUCR |= (1 << ISC10); // nastaveni preruseni od zmeny vstupu pro interrupt INT0
GIMSK |= (1 << INT1); // povoleni interruptu INT0
TCCR0B |= (1 << CS00); // Set up timer
sei(); // enable interrupts
while(1)
{
if(!DATA) // kdyz je 0 na datech
{
POVOLOVAK_HIGH; // zapni vysilani
bit=0; // vynuluj vsechny promenne pro mereni casu a pocitani bitu
TCNT0=0;
preteceni=0;
cas = 0xFFFF; // nastav cas delky bitu na nejvetsi mozny
while (bit <= 8) // odpocitej dobu 8mi bitu
{
if ((100+TCNT0+preteceni*0x0100) >= cas) // zkontroluj jestli necekame na dalsi bit dele nez je nekratsi znema delka bitu
{
TCNT0 = 0; // zacni znova merit cas do dalsiho mozneho bitu
preteceni=0;
bit++; // pokud jsme cekali dele, tak bit uz ubehl, to znamena, ze muzeme pocitadlo bitu posunout o jednicku
}
}
/* while (!DATA); // cekani na stop bit (detekce pripadneho paritniho bitu)
for (stopbit=2;stopbit >= 0;stopbit--) // odpocitej dva stopbity
{
while ((TCNT0+preteceni*0x0100) <= cas)
{
if(!DATA) break;
}
}*/
}
else POVOLOVAK_LOW; // kdyz je 1 prepni na prijem
}
return(0);
}