Мож кому будет интересно..

Принцип взят из этой темы http://electronix.ru/forum/index.php?showtopic=65996 + немного мозга. Отдельная благодарность ее учасникам за инфу

Контроллер - атемга88 на плате от какого-то старого проекта.
Датчики брал вот такие http://voron.ua/catalog/018090 дешевые. По скольку мне прислали не пару, а 2 передатчика - так и поставил. передатчик тоже OK работает в качестве приемника

Схема простая. добротности датчиков для расстояния 100мм (взял исходя из нужных критериев) достаточно, так что все прямо к мк. Компаратору опору немного сместил и поднял все это дело над землей.

Принцип основан на измерении разности фаз сигнала туда и обратно и выдача на комп по UART, дальше вся обработка на матлабе.
Тактовая частота 20мгц. резонансная около 42кгц(подстраивал).
У таймера1 2 прерывания в центре цикла и в конце, тоесть прерывания вылетают с частотой ~84кгц всегда из одного места: sleep; rjmp -1;
Код
OCR1B=TMVAL_PI-1; // middle
OCR1A=TMVAL_PI*2-1;
OCR1A=TMVAL_PI*2-1;
главное - успеть их обработать, до наступления следующего прерывания.
В обработчике собственно дрыгание ногами и проверка флага ICR, который выставляется по одному фронту(без разницы какому) компаратора.
CODE
static void tih1(){
PORTC^=(PC_US00|PC_US01);
icr1();
}
static void tih2(){
PORTC^=(PC_US12|PC_US13);
icr2();
}
void tihInit(){
setTih1();
}
ISR(iTmr1CmpA){ // full cycle, 40khz
pTih();
}
ISR(iTmr1CmpB){ // middle of cycle
pTih();
}
PORTC^=(PC_US00|PC_US01);
icr1();
}
static void tih2(){
PORTC^=(PC_US12|PC_US13);
icr2();
}
void tihInit(){
setTih1();
}
ISR(iTmr1CmpA){ // full cycle, 40khz
pTih();
}
ISR(iTmr1CmpB){ // middle of cycle
pTih();
}
В стейт-машине
1. делается 4096 холостых тактов
2. берется значение ICR, которое по сути является фазой(если свернуть к +-PI) и интегрируется 2048 раз
3. меняются местами приемник/передатчик
4. повторяется 1-3
5. вычисляется разность фаз(со сварачиванием ессно) выдается результат по uart ( cbkDfrdy(dfi); )
Разность фаз может быть как положительная, так и отрицательная, те можно мерять и направление ветра.
Вот примерно такой код
CODE
// --------------------------------------------------------
static CallbackF pTih;
static long g_integ;
static int g_icrint1,g_icrint2;
static U16 g_ctr;
static U8 g_st;
static void tih1();
static void tih2();
static void tmrReset(){
TCCR1B=(TCCR1B&~0x07);
TCNT1H=0;
TCNT1L=0;
TCCR1B|=(1<<CS10);
TIFR1=0x27;
}
static void setTih1(){
DIDR0=(1<<ADC2D)|(1<<ADC3D);
PORTC=0x30|PC_US00;
DDRC=PC_US00|PC_US12|PC_US01;
ADMUX=3;
pTih=tih1;
tmrReset();
}
static void setTih2(){
DIDR0=(1<<ADC0D)|(1<<ADC1D);
PORTC=0x30|PC_US12;
DDRC=PC_US00|PC_US12|PC_US13;
ADMUX=1;
pTih=tih2;
tmrReset();
}
#define T_PREAMBLE 4096
#define LS_INTC 11
static inline char getIcr(int *picr){
if(TIFR1&(1<<ICF1)){
int icr=ICR1L;
icr|=(U16)ICR1H<<8;
TIFR1=(1<<ICF1);
if(icr>=TMVAL_PI)icr-=TMVAL_PI*2; // if fi>=180 fi=fi-360;
*picr=icr;
return 1;
}
return 0;
}
static void icr1(){
int icr;
switch(g_st){
case 0: // start
g_ctr=0;
g_st=1;
break;
case 1:
if((++g_ctr)>=T_PREAMBLE){
g_ctr=0;
g_integ=0;
g_st=2;
}
break;
case 2:
if(!getIcr(&icr))break;
g_integ+=icr;
if((++g_ctr)>=(1<<LS_INTC)){
g_icrint1=g_integ>>LS_INTC;
g_st=0;
setTih2();
}
break;
default:
g_st=0;
break;
}
}
static void icr2(){
int icr;
switch(g_st){
case 0: // start
g_ctr=0;
g_st=1;
break;
case 1:
if((++g_ctr)>=T_PREAMBLE){
g_ctr=0;
g_integ=0;
g_st=2;
}
break;
case 2:
if(!getIcr(&icr))break;
g_integ+=icr;
if((++g_ctr)>=(1<<LS_INTC)){
g_icrint2=g_integ>>LS_INTC;
int dfi=g_icrint1-g_icrint2;
if(dfi>=TMVAL_PI)dfi-=TMVAL_PI*2; // wrap phase
else if(dfi<-TMVAL_PI)dfi+=TMVAL_PI*2;
cbkDfrdy(dfi);
//outhex(dfi);
//outhex(g_icrint1);uartch(' ');outhex(g_icrint2);
//uartstr_P("\r\n",2);
g_st=0;
setTih1();
}
break;
default:
g_st=0;
break;
}
}
static CallbackF pTih;
static long g_integ;
static int g_icrint1,g_icrint2;
static U16 g_ctr;
static U8 g_st;
static void tih1();
static void tih2();
static void tmrReset(){
TCCR1B=(TCCR1B&~0x07);
TCNT1H=0;
TCNT1L=0;
TCCR1B|=(1<<CS10);
TIFR1=0x27;
}
static void setTih1(){
DIDR0=(1<<ADC2D)|(1<<ADC3D);
PORTC=0x30|PC_US00;
DDRC=PC_US00|PC_US12|PC_US01;
ADMUX=3;
pTih=tih1;
tmrReset();
}
static void setTih2(){
DIDR0=(1<<ADC0D)|(1<<ADC1D);
PORTC=0x30|PC_US12;
DDRC=PC_US00|PC_US12|PC_US13;
ADMUX=1;
pTih=tih2;
tmrReset();
}
#define T_PREAMBLE 4096
#define LS_INTC 11
static inline char getIcr(int *picr){
if(TIFR1&(1<<ICF1)){
int icr=ICR1L;
icr|=(U16)ICR1H<<8;
TIFR1=(1<<ICF1);
if(icr>=TMVAL_PI)icr-=TMVAL_PI*2; // if fi>=180 fi=fi-360;
*picr=icr;
return 1;
}
return 0;
}
static void icr1(){
int icr;
switch(g_st){
case 0: // start
g_ctr=0;
g_st=1;
break;
case 1:
if((++g_ctr)>=T_PREAMBLE){
g_ctr=0;
g_integ=0;
g_st=2;
}
break;
case 2:
if(!getIcr(&icr))break;
g_integ+=icr;
if((++g_ctr)>=(1<<LS_INTC)){
g_icrint1=g_integ>>LS_INTC;
g_st=0;
setTih2();
}
break;
default:
g_st=0;
break;
}
}
static void icr2(){
int icr;
switch(g_st){
case 0: // start
g_ctr=0;
g_st=1;
break;
case 1:
if((++g_ctr)>=T_PREAMBLE){
g_ctr=0;
g_integ=0;
g_st=2;
}
break;
case 2:
if(!getIcr(&icr))break;
g_integ+=icr;
if((++g_ctr)>=(1<<LS_INTC)){
g_icrint2=g_integ>>LS_INTC;
int dfi=g_icrint1-g_icrint2;
if(dfi>=TMVAL_PI)dfi-=TMVAL_PI*2; // wrap phase
else if(dfi<-TMVAL_PI)dfi+=TMVAL_PI*2;
cbkDfrdy(dfi);
//outhex(dfi);
//outhex(g_icrint1);uartch(' ');outhex(g_icrint2);
//uartstr_P("\r\n",2);
g_st=0;
setTih1();
}
break;
default:
g_st=0;
break;
}
}
Самое важное здесь выполнить tmrReset в начале каждого измерения иначе фаза будет прыгать рандомически. Ну и успеть полностью обработать прерывание(когда идет замер фазы) примерно за 230 тактов, в моем случаи.
Мне нужно мерять не скорость ветра, а расход воздуха, м3/час. Поэтому эта колбаса помещается в трубе диаметром 125мм.
Формулы простые, все основано на Википедии + Wolfram mathematica

l=0.1; % расстояние между датчиками
d=0.125; % диаметр трубы
vs0=20.0457*sqrt(t+273.15); % скорость звука, t - температура в °C, берется с термодатчика тем же прибором.
dt=y/20e6; % y-разность фаз.
v=-l/dt + sqrt(l^2 + dt^2* vs0^2)/dt; % вычисляем скорость ветра, м/с
va=v*pi*(d/2)^2*3600; % расход воздуха, м3/час
Вот так выглядит результат. Пока тест, дул ртом (в одну и в другую сторону)

